iptables:発信トラフィックをconntrackおよび所有者と照合します。奇妙な滴で動作します


11

私のiptablesスクリプトでは、できる限り細かいルールを書く実験を行っています。一部のユーザーはセキュリティを確保し、一部は学習課題として、どのユーザーがどのサービスを使用できるかを制限します。

3.6.2カーネルを実行しているDebian 6.0.6でiptables v1.4.16.2を使用します。

しかし、まだよくわからない問題が発生しました。

すべてのユーザーの送信ポート

これは完璧に機能します。一般的な状態追跡ルールはありません。

##発信ポート81
$ IPTABLES -A OUTPUT -p tcp --dport 81 -m conntrack --ctstate NEW、ESTABLISHED -j ACCEPT
$ IPTABLES -A INPUT -p tcp --sport 81 -s $ MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT

ユーザーが一致する送信ポート

##ユーザーアカウントの送信ポート80
$ IPTABLES -A OUTPUT --match owner --uid-owner useraccount -p tcp --dport 80 -m conntrack --ctstate NEW、ESTABLISHED --sport 1024:65535 -j ACCEPT
$ IPTABLES -A INPUT -p tcp --sport 80 --dport 1024:65535 -d $ MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT

これにより、アカウント「useraccount」に対してのみポート80が許可されますが、TCPトラフィックに対するこのようなルールには問題があります。

##デフォルトの送信ログ+ブロックルール
$ IPTABLES -A OUTPUT -j LOG --log-prefix "BAD OUTGOING" --log-ip-options --log-tcp-options --log-uid
$ IPTABLES -A OUTPUT -j DROP

問題

上記は機能し、ユーザー「useraccount」はファイルを完全に正常に取得できます。システム上の他のユーザーは、ポート80への発信接続を行うことができません。

useraccount @ host:$ wget http://cachefly.cachefly.net/10mb.test

しかし、上記のwgetは私のsyslogにx7のドロップされたエントリを残します:

10月18日02:00:35 xxxxカーネル:悪い送信IN = OUT = eth0 SRC = xx.xx.xx.xx DST = 205.234.175.175 LEN = 40 TOS = 0x00 PREC = 0x00 TTL = 64 ID = 12170 DF PROTO = TCP SPT = 37792 DPT = 80 SEQ = 164520678 ACK = 3997126942 WINDOW = 979 RES = 0x00 ACK URGP = 0  

UDPトラフィックを使用する同様のルールでは、これらのドロップは発生しません。どのユーザーがDNS要求を行うことができるかを制限するルールが既に用意されています。

ドロップされた発信ACKパケットは、理解できないルートアカウント(URGP = 0)から送信されているようです。ユーザーアカウントをrootに入れ替えても。

3ウェイハンドシェイクの3番目のステップの後でconntrackが接続の追跡を開始するため、ACKパケットは新しいものとして分類されていると思いますが、なぜドロップされるのですか?

これらの低下は安全に無視できますか?

編集する

したがって、私は次のようなルールをよく目にします。

$ IPTABLES -A OUTPUT -s $ MYIP -p tcp -m tcp --dport 80 -m state --state NEW、ESTABLISHED -j ACCEPT
$ IPTABLES -A INPUT -p tcp -m tcp --sport 80 -d $ MYIP -m state --state ESTABLISHED -j ACCEPT

状態の一致が明らかに廃止されたため、「-m state --state」を「-m conntrack --ctstate」に交換しました。

一般的な状態追跡ルールを作成することはベストプラクティスですか?上記のルールは正しいと見なされていませんか?

発信ユーザー接続を厳密に制御するには、このようなものが良いでしょうか?

$ IPTABLES -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
$ IPTABLES -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

$ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner useraccount -j ACCEPT

$ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner otheraccount -j ACCEPT

このホストもLANからのトラフィックをルーティングしている場合、FORWARDチェーンとNATテーブルを含むすべてのルールを投稿してください。
Serge

このホストはルーティングを実行していないため、トラフィックはこれらのルールを持つマシンから発信されます。特定の発信トラフィックに関連するルールのみを投稿しました。
arcX

回答:


16

簡単に言えば、ソケットが誰にも属していないときにそのACKが送信されました。ユーザーxに属するソケットに関係するパケットを許可する代わりに、ユーザーからのソケットによって開始された接続に関係するパケットを許可しますx

長い話。

問題を理解するにはwget、HTTPリクエストが一般的にどのように機能するかを理解することが役立ちます。

wget http://cachefly.cachefly.net/10mb.test

wgetがへのTCP接続を確立し、確立されるcachefly.cachefly.netと、次のようなHTTPプロトコルで要求を送信します:「/10mb.testGET /10mb.test HTTP/1.1)のコンテンツを私に送信してください。ところで、完了したら接続を閉じないでください(Connection: Keep-alive)。理由これは、サーバーが同じIPアドレス上のURLのリダイレクトで応答した場合に、接続を再利用できるためです。

これでサーバーはどちらかで応答できます。「ここに、要求されたデータが表示されます。これは10MBの大きさ(Content-Length: 10485760)であることに注意してください。そうです、接続は開いたままにしておきます。」または、データのサイズがわからない場合は、「ここにデータがあります。接続を開いたままにすることはできませんが、接続の終わりを閉じてデータのダウンロードを停止できる場合は通知します。」

上記のURLでは、最初のケースです。

したがって、wget応答のヘッダーを取得するとすぐに、10MBのデータをダウンロードすると、そのジョブが完了したことがわかります。

基本的には、wget10MBが受信されて終了するまでデータを読み取ります。しかし、その時点で、やるべきことはまだあります。サーバーはどうですか?接続を開いたままにするように言われました。

終了する前に、ソケットのファイル記述子をwget閉じます(closeシステムコール)。すると、closeシステムはサーバーから送信されたデータの確認を終了し、FIN「これ以上データを送信しません」と言うを送信します。その時点でclose戻り、wget終了します。TCP接続に関連付けられたソケットはもうありません(少なくとも、ユーザーが所有しているソケットはありません)。しかし、それはまだ終わっていません。これを受信するFINと、HTTPサーバーはクライアントからの次の要求を読み取るときにファイルの終わりを確認します。HTTPでは、これは「これ以上の要求はありません。終わりを閉じます」を意味します。したがって、FINも送信します。「私も何も送信しません。その接続はなくなります」と言います。

そのFINを受信すると、クライアントは「ACK」を送信します。しかし、その時点でwgetは、もうなくなっているため、ACKはどのユーザーからも送信されません。これが、ファイアウォールによってブロックされている理由です。サーバーはACKを受信しないため、あきらめるまでFINを繰り返し送信し、ドロップされたACKがさらに表示されます。つまり、これらのACKをドロップすることにより、かなり長い間、サーバーのリソース(ソケットをLAST-ACK状態に維持する必要がある)を不必要に使用することになります。

クライアントが「Keep-alive」を要求しなかった場合、またはサーバーが「Keep-alive」で応答しなかった場合の動作は異なります。

すでに述べたように、接続トラッカーを使用している場合、ESTABLISHED状態とRELATED状態のすべてのパケットを通過させ、パケットのみを考慮しNEWます。

NEWユーザーからのパケットを許可し、ユーザーからのパケットは許可しxない場合y、ユーザーによる確立された接続の他のパケットxが通過します。これは、ユーザーによって確立された接続ができないためyです(NEW接続を確立するパケットをブロックしているため)。ユーザーy接続が通過するパケットはありません。


3

これにより、アカウント「useraccount」に対してのみポート80が許可されます。

—ええと、少なくとも、あなたが示したルールは、実際にはこれを意味するものではありません。

アドバイスの余地もあります— ESTABLISHEDストリームに対してユーザーチェックを行わず、NEWに対してのみチェックしてください。Incoming ESTABLISHEDをチェックするときにソースポートをチェックするポイントもわかりません。どのポートとの違いは何ですか。それはconntrackのPoVからすでにESTABLISHED状態です。ファイアウォールはできるだけシンプルで効率的である必要があるため、Occamのかみそりアプローチが最適です。


1
アドバイスありがとうございます。通常、私は単純化のためにすべてですが、それがこの特定の演習のポイントではありません。
arcX

1
@arcX、この演習は複雑すぎて一貫性がないために失敗する可能性があります— IOW、表示される動作はnetfilterの内部(バグ、癖)によるものではなく、使用方法によるものです。最初にルールセットを簡略化してみてください
poige '20
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.