iptables と netfilterを勉強し直す(ゼロからのfirewall構築)その2
前回の続きです
/etc/iptables/rules.v4を編集して基礎ルールを追加する
前回の最後に説明した方法で、基礎的なルールを追加していきます。
vi /etc/iptables/rules.v4
# Generated by iptables-save v1.8.7 on Sun Jan 9 11:57:32 2022
*filter
:INPUT DROP [3:219]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [454:42121]
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p udp -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A INPUT -d 127.0.0.0/8 ! -i lo -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
COMMIT
# Completed on Sun Jan 9 11:57:32 2022
今回は上の9~12行目を追加します。
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEP
ループバックデバイスを用いた内部通信をINPUT/OUTPUTともに通過させます。
iptables -A INPUT -d 127.0.0.0/8 ! -i lo -j REJECT --reject-with icmp-port-unreachable
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
ICMPエコー(ping)に関しては、こちらからのpingが届かない相手からのリクエストを遮断し、その後で残りすべてのICMPエコーを受け入れます。
ファイルを保存したら、以下のコマンドで iptablesにファイルを再読込させます
netfilter-persistent reload
iptables -L を使った確認では、どのデバイスを使っているかなどがはっきり表示されないので、今回は iptables -vnL で確認してみましょう
Chain INPUT (policy DROP 107 packets, 18261 bytes)
pkts bytes target prot opt in out source destination
750 51992 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
2 204 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
4 304 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
0 0 REJECT all -- !lo * 0.0.0.0/0 127.0.0.0/8 reject-with icmp-port-unreachable
10 840 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 670 packets, 117K bytes)
pkts bytes target prot opt in out source destination
6 508 ACCEPT all -- * lo 0.0.0.0/0 0.0.0.0/0
通過パケット量、使用するデバイス(Loなのかeth0なのか)、宛先のアドレスすべて詳細に表示されます。基本的にこの繰り返しで作業を進めます。
hashlimitを使って攻撃に対処する
iptables には hashlimit というモジュールがあり、特定の宛先からの通信数を制限することができます。ブルートフォースアタックなどに対して有効です。基本的な概念としては、
1.初めて通信を行った相手に回数券を渡す
2.新しく通信をするたびに回数券を1枚づつ消費していく
3.特定の分数ごとに回数券を追加させることができる
4.回数券を使い切ると1時的にBANされて通信できなくなる
5.特定の時間がすぎると、BANリストから削除され、1に戻る
と言った感じのようです。いままでの記述に -m state –state NEW(新規接続に限り有効) を追加して、「宛先ポート番号」と「-j ACCEPT」の間に以下を追記するだけで設定できます。
# Hashlimitモジュールの使用開始
-m hashlimit
# 1分に1枚回数券を追加
–hashlimit 1/m
# 回数券の初期枚数は6枚
–hashlimit-burst 6
# 通信は送信元IPとポートのペアで管理する
–hashlimit-mode srcip,dstport
# sshlimitという名前で管理する
–hashlimit-name sshlimit
# 120秒(120000ミリ秒)でリセットする
–hashlimit-htable-expire 120000
つまり、192.168.1.100というアドレスを持つ機器が22番ポートにアクセスする場合、最初の1分は6回までアクセス可能、それ以降は1分に1回だけアクセス可能、通信を2分間停止させた場合は、また1分6回までアクセス可能……というように「不必要な回数の通信を行う相手」に対して、門戸を狭めるように働きます。
具体的には、/etc/iptables/rules.v4 のsshに関する記述を以下のように書き換えます。
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -m hashlimit --hashlimit 1/m --hashlimit-burst 20 --hashlimit-mode srcip,dstport --hashlimit-name sshlimit --hashlimit-htable-expire 120000 -j ACCEPT
それから reload します
netfilter-persistent reload
実際に連続してssh接続を仕掛けると、7回目でブロックされて通信できなくなります。サーバ内に /proc/net/ipt_hashlimit/{定義した管理名} ファイルが存在していたら、ブロックされている証拠です。ファイルには、「カウント秒数、ソースIP、宛先IP、ポート、それからブロック管理に使っているのであろう謎の数値」が書かれています。
cat /proc/net/ipt_hashlimit/sshhlimit
55 192.168.1.140:0->0.0.0.0:22 10824142247960832 24739011540000000 8246337180000000
なお、hashlimitにはセーフリスト(ホワイトリスト)的なものはありません。セーフリストを設定したい場合は前回説明した「iptablesは上から順に処理される」というルールを思い出して、hashlimitの記述の1行上に以下を書いておきましょう。192.168.1.1からの22番ポートへの通信はすべて許可されます。
-A INPUT -s 192.168.1.1 -p tcp -m tcp --dport 22 -j ACCEPT
(次回に続く)