Ubuntuデスクトップのファイアウォールを設定してみた

注意:以下の内容はUbuntu Desktop版での話です。Server版はまた別です。

ポートは塞がれているというよりは開けてないだけ

Ubuntuでは標準で全てのポートが閉じているのでファイアウォールの設定は不要」などという文章をよく見かけるのだが、これはものすごい誤解を招いていると思う。
実際はポートを開けてLISTENするプログラムが標準では入っていない(設定されていない)というだけで、明示的に全てのポートがブロックされるように設定されているわけではない。
少なくとも今年の7月にUbuntu(8.04)を使い始めた時にはiptablesの定義も空っぽだったし、他のそれらしい設定も何もなかった。


この状態でApacheとか入れると当然のように80番ポートでLISTENし始めて、外部からもアクセスできるようになる。Apacheなど入れなくてもNautilusなどでファイルの共有設定をすれば、当然それに必要なポートが開く。そりゃそうだ。他にもバックグラウンド的な何かが動いてそうな気もする。


自分はこれを誤解していて、外部からの新規接続は全てブロックするように設定されていて、Apacheとかを立ち上げてもローカル内でしかアクセスできないよう良きに計らってくれているものだと思っていた。

iptablesによるフィルタリング設定

普通はデスクトップPCにサーバアプリなんて入れないからそれでも問題ないのかもしれないけど、WebエンジニアとしてはついついローカルにApacheとか入れちゃったりするので何かしら対策はしておきたいところ。*1


というわけでiptablesファイアウォールの設定をしてみた。
Ubuntuではufwとかいうのを使うらしいんだけど、なにそれ食べられるの?状態だったので、いつも通りにiptablesコマンドを直に叩く。

1.自動起動するための下準備

Ubuntuiptablesはシステムの起動時に自動的に設定を復元してくれるようにはなってないので、まずはそれを行う。

具体的には/etc/init.d/iptablesを用意してsysv-rc-confでランレベル毎に自動起動するように設定するだけなんだけど、元になるスクリプトがどこにもないので、ぐぐって見つけたUbuntuのフォーラムから拾ってくる。


http://ubuntuforums.org/archive/index.php/t-19106.html


導入方法も書いてあるのでその通りにするだけ。
ちなみにCentOS4からコピってきたものは動かなかった。


ともあれこれで/etc/init.d/iptables start|stop|saveができるようになったので、適当に設定してsaveして、システム起動時にstartするようにしておけば準備は完了。

2.設定を書いたスクリプトを用意

手で打ち込んでいくのはだるい、というか間違えると切ないのでシェルスクリプトにまとめる。
サーバ用のものを元にしてデスクトップで不要なもの必要なものを調整したものが以下のスクリプト
ルータの内側にいるクライアントなのでSSHサーバの設定や東アジアフィルタなどは削った。OUTPUTの制限も省略。
Apacheはローカルだけでもよかったんだけど、同僚に見てもらったりするときのために開いている。
内側にいるという意味ではDoS系の防御設定もあまり意味がないのかもしれないが、やれることはやっておくに超したことはないので。


IP MessengerはメッセージだけならUDPでいいんだけど、ファイル転送をするにはTCPも開けなければいけない。
最初これに気づかずにはまった。

#!/bin/bash

LOCALNET='xxx.xxx.xxx.xxx/12'
INTERNAL_IP=`ifconfig eth0 | grep 'inet addr' | awk '{print $2}' | awk -F : '{print $2}'`

# ゲートウェイ
EXTERNAL_IP='xxx.xxx.xxx.xxx'


# NATの設定を削除
#iptables -F -t nat
#iptables -F -t mangle
# 全てのルールを削除
iptables -F
# 全てのユーザ定義チェインを削除
iptables -X

iptables -Z


# 基本的には外部からのパケットの通過を拒否
iptables -P INPUT DROP
# 基本的には外部へのパケットの通過を許可
iptables -P OUTPUT ACCEPT
# 基本的には他のインターフェイスへ再送信を拒否
iptables -P FORWARD DROP

# lo( ループバック)からのINPUTを許可
iptables -A INPUT -i lo -j ACCEPT
# lo( ループバック)からのOUTPUTを許可
iptables -A OUTPUT -o lo -j ACCEPT

# 確立しているコネクションのINPUTを許可
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 確立しているコネクションのOUTPUTを許可
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT


# DNS
iptables -A OUTPUT -m state --state NEW -m tcp -p tcp --sport 53 -j ACCEPT
iptables -A OUTPUT -p udp -m udp --sport 53 -j ACCEPT
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 953 -j ACCEPT

# LSLDNS
iptables -A INPUT -p udp --dport 5353 -d 224.0.0.251 -j ACCEPT

# DHCP
iptables -A INPUT -i eth0 -d 255.255.255.255 -p udp --dport 67 --sport 68 -j ACCEPT

# IPスプーフィング対策
iptables -N ip_spoofing
iptables -A ip_spoofing -m limit --limit 1/s --limit-burst 5 -j LOG --log-prefix '[iptables ip_spoofing] '
iptables -A ip_spoofing -j DROP
iptables -A INPUT -i eth0 -s 0.0.0.0/8 -j ip_spoofing
iptables -A INPUT -i eth0 -s 10.0.0.0/8 -j ip_spoofing
iptables -A INPUT -i eth0 -s 127.0.0.0/8 -j ip_spoofing
iptables -A INPUT -i eth0 -s 169.254.0.0/16 -j ip_spoofing
#iptables -A INPUT -i eth0 -s 172.16.0.0/12 -j ip_spoofing
iptables -A INPUT -i eth0 -s 192.0.2.0/24 -j ip_spoofing
#iptables -A INPUT -i eth0 -s 192.168.0.0/16 -j ip_spoofing
iptables -A INPUT -i eth0 -s 224.0.0.0/4 -j ip_spoofing
iptables -A INPUT -i eth0 -s 240.0.0.0/5 -j ip_spoofing
iptables -A INPUT -i eth0 -s 248.0.0.0/5 -j ip_spoofing
iptables -A INPUT -i eth0 -s 255.255.255.255/32 -j ip_spoofing
# 自分のグローバルアドレスによるeth0からのアクセスを拒否
#iptables -A INPUT -i eth0 -s $EXTERNAL_IP -j DROP

# Ping of Death対策
iptables -N ping-of-death
iptables -A ping-of-death -m limit --limit 3/s --limit-burst 12 -j ACCEPT
iptables -A ping-of-death -m limit --limit 1/m --limit-burst 5 -j LOG --log-level info --log-prefix '[iptables ping-of-death] '
iptables -A ping-of-death -j DROP
iptables -A INPUT -i eth0 -p icmp --icmp-type echo-request -j ping-of-death
iptables -A FORWARD -i eth0 -p icmp --icmp-type echo-request -j ping-of-death

# SYNフラッド攻撃対策
iptables -N syn-flood
iptables -A syn-flood -m limit --limit 3/s --limit-burst 12 -j RETURN
iptables -A syn-flood -m limit --limit 1/m --limit-burst 5 -j LOG --log-level info --log-prefix '[iptables syn-flood] '
iptables -A syn-flood -j DROP
iptables -A INPUT -i eth0 -p tcp --syn -j syn-flood
iptables -A FORWARD -i eth0 -p tcp --syn -j syn-flood

# ポートスキャン対策
iptables -N port-scan
iptables -A port-scan -m limit --limit 3/s --limit-burst 12 -j RETURN
iptables -A port-scan -m limit --limit 1/m --limit-burst 5 -j LOG --log-level info --log-prefix '[iptables port-scan] '
iptables -A port-scan -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j port-scan
iptables -A FORWARD -i eth0 -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j port-scan

# NTP
iptables -A INPUT -p udp --dport 123 -j ACCEPT

# IPsec
#iptables -A INPUT -p 50 -j ACCEPT
#iptables -A INPUT -p 51 -j ACCEPT

# Samba
iptables -A INPUT -s $LOCALNET -p udp --dport 137 -j ACCEPT
iptables -A INPUT -s $LOCALNET -p udp --dport 138 -j ACCEPT
iptables -A INPUT -s $LOCALNET -p tcp --dport 139 -j ACCEPT
iptables -A INPUT -s $LOCALNET -p tcp --dport 445 -j ACCEPT

# HTTP/HTTPS
iptables -A INPUT -s $LOCALNET -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -s $LOCALNET -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT

# PostgreSQL
#iptables -A INPUT -s $LOCALNET -m state --state NEW -m tcp -p tcp --dport 5432 -j ACCEPT

# CUPS
#iptables -A INPUT -s $LOCALNET -p udp -m udp --dport 631 -j ACCEPT

# IP Messenger
iptables -A INPUT -s $LOCALNET -p tcp -m tcp --dport 2425 -j ACCEPT
iptables -A INPUT -s $LOCALNET -p udp -m udp --dport 2425 -j ACCEPT

# ICMP
#iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited

INTERNAL_IPのところは自分のIPアドレスを設定するんだけど、DHCPなのでどうしたらいいのかわからなかったので無理矢理引っこ抜いた。もう少しいいやり方はないんだろうか。


というわけで、一通り設定してみたけどなんか無駄なことしてる気がしてきた。つーか、むしろクライアントの場合はOUTPUTを制限するべき?
正直理解できてない部分もあるので、おかしい点があればコメント欄へおながいします。

*1:開発は専用環境や仮想マシンでやるけど、ちょっとした確認とかにローカル環境を使ったりもする。