さくらのVPSのファイアウォール(iptables)設定

#環境と概要
さくらVPS（CentOS 6.7）

[こちら](http://blog.uklab.jp/web/setting-sakura-vps-01/)の内容でFWを設定していたが、2日に1回のペースで接続障害が発生するため、設定を新しくする
##求める機能

- 各種攻撃(IP Spoofingなど)に対応
- 国ごとのアクセス制御が可能
- 設定の更新が高速

##搭載する機能

- 特定国（中国、インド、エジプト、パキスタン、ロシア）からのアクセスを遮断
- 任意のIPアドレスからのアクセスを遮断
- SSHへの国外からのアクセスを遮断
- IP Spoofing攻撃、ICMP Flood攻撃、Smurf攻撃、SYN Flood攻撃を遮断
- DNS Amp攻撃、DNSポイズニング攻撃を検知（DNS使用時）
- 国別IPアドレスの取得（毎日）
- 設定更新に掛る時間が数秒


##参考リンク
[iptablesの設定ファイルをシェルスクリプトを利用して動的に作成 | OXY NOTES](http://oxynotes.com/?p=6401)
[iptablesをシェルスクリプトで設定していて動作が遅い場合の対処法 | OXY NOTES](http://oxynotes.com/?p=9770)
[さくらのVPSへのiptablesの設定 | 9ensanのLifeHack](http://9ensan.com/blog/server/sakura-vps-iptables/)
[ファイアウォール構築(iptables) - CentOSで自宅サーバー構築](http://centossrv.com/iptables.shtml)

#前準備
Smurf攻撃対策に必要な「ディレクティッド・ブロードキャスト・アドレス」の確認と、スクリプト保存領域の作成

##「ディレクティッド・ブロードキャスト・アドレス」の確認
Smurf攻撃対策に必要な「ディレクティッド・ブロードキャスト・アドレス」を取得

次のコマンドを入力

`ifconfig`

`Bcast:192.168.0.255`の部分がディレクティッド・ブロードキャスト・アドレス

```
eth0      Link encap:Ethernet  HWaddr AA:BB:CC:DD:EE:FF
          inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0
```

##スクリプト保存領域の作成
次のコマンドを入力

```
mkdir /usr/script/
```

#各スクリプトの作成

「iptables.sh」で新規作成

```
vi /usr/script/iptables.sh
```

次のシェルをコピペ

```shell:iptables.sh
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

cat << EOS
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:ACCEPT_JP_FILTER - [0:0]
:DNSAMP - [0:0]
:DROP_COUNTRY_FILTER - [0:0]
:PING_ATTACK - [0:0]

# 拒否IPリストに記載されたIPを拒否
EOS
if [ -s /root/deny_ip ]; then
     for ip in `cat /root/deny_ip`
     do
          echo -A INPUT -s $ip -j DROP
     done
fi

cat << EOS

# IP Spoofing攻撃対策
-A INPUT -i eth0 -s 127.0.0.1/8 -j DROP
-A INPUT -i eth0 -s 10.0.0.0/8 -j DROP
-A INPUT -i eth0 -s 172.16.0.0/12 -j DROP
-A INPUT -i eth0 -s 192.168.0.0/16 -j DROP
-A INPUT -i eth0 -s 192.168.0.0/24 -j DROP

# Ping攻撃対策 + Ping Flood攻撃対策
-A PING_ATTACK -m length --length 0:85 -m limit --limit 1/sec --limit-burst 4 -j ACCEPT
-A PING_ATTACK -j LOG --log-prefix "[IPTABLES PINGATTACK] : " --log-level 7
-A PING_ATTACK -j DROP
-A INPUT -p icmp --icmp-type 8 -j PING_ATTACK

# Smurf攻撃対策+不要ログ破棄
-A INPUT -d 255.255.255.255/32 -j DROP
-A INPUT -d 224.0.0.1/32 -j DROP
-A INPUT -d 192.168.0.255/32 -j DROP

# Auth/IDENT用の113番ポートは拒否
-A INPUT -i eth0 -p tcp -m tcp --dport 113 -j REJECT --reject-with tcp-reset

# 日本からのアクセスを許可するチェインを作成
EOS
if [ -s /tmp/iplist ]; then
     sed -n 's/^JP\t//p' /tmp/iplist | while read address;
     do
          echo -A ACCEPT_JP_FILTER -s $address -j ACCEPT
     done
fi

cat << EOS

# 特定の国からのアクセスを拒否するチェインを作成して追加
# 中国、インド、エジプト、パキスタン、ロシア
EOS
if [ -s /tmp/iplist ]; then
     sed -n 's/^\(CN\|IN\|EG\|\PK|RU\)\t//p' /tmp/iplist | while read address;  do
          echo -A DROP_COUNTRY_FILTER -s $address -j DROP
     done
     echo -A INPUT -j DROP_COUNTRY_FILTER
fi

cat << EOS

# ステートフル・パケットインスペクションで正しいTCPと既に許可された接続を許可
-A INPUT -p tcp -m tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW -j DROP
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# lo（ループバックインターフェース）の許可
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

#------------------------------------------------------------------
#  ここから下は使用するサービスによって変える
#------------------------------------------------------------------

# SSHを日本からのみ許可
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 100 --hashlimit-mode srcip --hashlimit-name ssh-limit --hashlimit-htable-expire 3600000 -j ACCEPT_JP_FILTER

# httpを許可
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT

# DNSを許可。DNS Ampやカミンスキー攻撃対策にログを取る
-A INPUT -i eth0 -p udp -m state --state NEW -m udp --dport 53 -j DNSAMP
-A DNSAMP -m recent --set --name dnsamp --rsource
-A DNSAMP -m recent --rcheck --seconds 60 --hitcount 10 --name dnsamp --rsource -j LOG --log-prefix "[IPTABLES DNSAMP] : " --log-level 7
-A DNSAMP -m recent --rcheck --seconds 60 --hitcount 10 --name dnsamp --rsource -j DROP
-A DNSAMP -j ACCEPT

-A INPUT -p tcp -m state --state NEW -m tcp --dport 53 -j ACCEPT

# smtpsを許可
-A INPUT -p tcp -m state --state NEW -m tcp --dport 465 -j ACCEPT

# imaps(pop3 protocol over TLS/SSL)を許可
-A INPUT -p tcp -m state --state NEW -m tcp --dport 993 -j ACCEPT

# pop3s(imap4 protocol over TLS/SSL)を許可
-A INPUT -p tcp -m state --state NEW -m tcp --dport 995 -j ACCEPT

# smtp tcpを許可
-A INPUT -p tcp -m state --state NEW -m tcp --dport 25 -j ACCEPT

# サブミッションポートを許可
-A INPUT -p tcp -m state --state NEW -m tcp --dport 587 -j ACCEPT

# https(http protocol over TLS/SSL) を許可
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT

# NTPを許可
-A INPUT -p udp -m state --state NEW -m udp --dport 123 -j ACCEPT

#------------------------------------------------------------------
#  ここから上は使用するサービスによって変える
#------------------------------------------------------------------

# 上記の条件に当てはまらない通信を記録して破棄
-A INPUT -m limit --limit 1/sec -j LOG --log-prefix "[IPTABLES DROP INPUT] : " --log-level 7
-A INPUT -j DROP

COMMIT
EOS
```

次の部分の最終行は取得した「ディレクティッド・ブロードキャスト・アドレス」に変更

```
# Smurf攻撃対策+不要ログ破棄
-A INPUT -d 255.255.255.255/32 -j DROP
-A INPUT -d 224.0.0.1/32 -j DROP
-A INPUT -d 192.168.0.255/32 -j DROP
```

また、使用するサービスの部分も変更すること。その際、最後の「上記の条件に当てはまらない通信を記録して破棄」の部分は消さないように注意する。

実行権限を付与

```
chmod 755 /usr/script/iptables.sh
```

##拒否IPリスト
次のコマンドを入力

```
vi /root/deny_ip
```

アクセスを拒否したいIPアドレスを入力して保存

##各種攻撃対策用スクリプト
「cyber_attack_block.sh」で新規作成

```
vi /usr/script/cyber_attack_block.sh
```

次のシェルをコピペ

```shell:cyber_attack_block.sh
# Smurf攻撃対策
sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1 > /dev/null
sed -i '/# Disable Broadcast Ping/d' /etc/sysctl.conf
sed -i '/net.ipv4.icmp_echo_ignore_broadcasts/d' /etc/sysctl.conf
echo "# Disable Broadcast Ping" >> /etc/sysctl.conf
echo "net.ipv4.icmp_echo_ignore_broadcasts=1" >> /etc/sysctl.conf
 
# SYN flood攻撃対策でSYN cookiesを有効に設定
sysctl -w net.ipv4.tcp_syncookies=1 > /dev/null
sed -i '/# Enable SYN Cookie/d' /etc/sysctl.conf
sed -i '/net.ipv4.tcp_syncookies/d' /etc/sysctl.conf
echo "# Enable SYN Cookie" >> /etc/sysctl.conf
echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf
```

同様に実行権限を付与

```
chmod 755 /usr/script/cyber_attack_block.sh
```

##国別IPアドレス一覧取得スクリプト
「iplist_check.sh」で新規作成

```
vi /etc/cron.daily/iplist_check.sh
```

次のシェルをコピペ

```shell:iplist_check.sh
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
# ファイルの取得
wget -q http://nami.jp/ipv4bycc/cidr.txt.gz -P /tmp
 
# 解凍してリネーム
gunzip -q -f -c /tmp/cidr.txt.gz > /tmp/iplist.new
 
# /tmp下なので240時間で自動的に削除されますが、念のため削除
rm -f /tmp/cidr.txt.gz
 
# iplistが存在しているかチェック
if [ -s /tmp/iplist ]; then
 
     # diffでエラーが出るので実行権限の変更。「-f」を付けて初回にファイルがない場合に対応
     chmod -f 700 iplist.new
     chmod -f 700 iplist
      
     # 差分チェック（正常にファイルが取得できたかチェック）
     # grep -c パターンに一致した行の行数のみを出力する。diffで差分（違い）のある行は「< hoge」と表示されるため、行頭に「<」がある行をカウントしている。「=」の前後にスペースがあると正常に代入できないので注意。
     # $()の中に記述しているので、変数ipdiffに代入。
     ipdiff=$(diff /tmp/iplist /tmp/iplist.new | grep -c "^<")
 
     # 上記が存在していて、差分の数が1000行以上の場合
     # （通常考えられない量の変更＝ファイルが正常に取得できていないと判断）
     if [ $ipdiff -gt 1000 ]; then
          # メールでIPリストが正常に取得できなかった由を伝える。
          cat <<EOS | mail -s "iplist_check" info@example.com
          iplist false
EOS
          # 正常に取得できなかったリストを破棄
          rm -f /tmp/iplist.new
     else
          # 正常に取得できた場合ファイル名をiplistに変更
          mv /tmp/iplist.new /tmp/iplist
 
          # 新しく取得したリストでiptablesの設定スクリプトを実行
 
          # まずは設定を保存する /etc/sysconfig/iptables.bakとして保存される
          /sbin/service iptables save
 
          # 設定を/etc/sysconfig/iptablesに書き込む
          sh /usr/script/iptables.sh >/etc/sysconfig/iptables
 
          # SYN cookies等の設定
          sh /usr/script/cyber_attack_block.sh
 
          # 書き込んだファイルをiptablesで読み込む（reloadだと不具合あるので注意）
          /sbin/service iptables restart
 
          # メールでIPリストが正常に取得できた由と変更されたIPの数を伝える。
          cat <<EOS | mail -s "iplist_check" info@example.com
          iplist true change IP $ipdiff
EOS
     fi
else
     # 初回実行時は差分をチェックすべきバックアップがないのでそのままファイル名を変更して利用
     mv /tmp/iplist.new /tmp/iplist
     /sbin/service iptables save
     sh /usr/script/iptables.sh >/etc/sysconfig/iptables
     sh /usr/script/cyber_attack_block.sh
     /sbin/service iptables restart
fi
```

次の部分のメールアドレスを変更
2つあるので注意

```
# メールでIPリストが正常に取得できなかった由を伝える。
cat <<EOS | mail -s "iplist_check" info@example.com
```

同様に実行権限を付与

```
chmod 755 /etc/cron.daily/iplist_check.sh
```

スクリプトを実行

```
sh /etc/cron.daily/iplist_check.sh
```