はじめに
2021年、CentOSが一つの区切りを迎えた。色々悩んだが、ubuntuに乗り換えた。勝手が違って苦労したので備忘録のつもりでメモ。
2022年3月、改定しました。
2022年4月、一覧を公開してくれているnami.jpさんに負荷がかかる記述だったので再度改定しました。
2022年8月、細かな部分を改定しました。
【注意とお願い】
2022年以降、不正アクセス、アカウント乗っ取り、個人情報流出のニュースが後を絶ちません。同じアクセス元から何度もアクセスされるといずれはパスワードが破られます。IDパスワードで認証するようなサービス(メールサーバーとか)を提供する場合、必ず動的ファイヤーウォールを構築しましょう。筆者のサーバーは日本の乗っ取られたサーバーからも不正アクセスチャレンジされてます。
iptablesの設定を永続化する
まずはiptablesの設定が永続化されるパッケージをインストール。これを入れないと再起動の度に設定が消えてしまう。sleepenhは動的なファイヤーウォール構築のスクリプトで使用する。
apt install iptables-persistent sleepenh
ルールを作成するスクリプトを書く
続いてiptablesを設定するためのスクリプトを作成。ufw?知らんわそんなもん。
国コードを指定してブロックするところは、各自の運用状況にて判断。僕は実際の運用環境では50か国以上ブロックしています。サーバーが提供するサービスが諸外国に対して本当に必要なのかどうか、セキュリティリスクと提供チャンスのバランスを見極めて設定しましょう。
vi makerules.sh
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin
###########################################################################################
# IPTABLESのルールを作成します。cidr.txtがダウンロードされていることが前提です。
# -A チェーンの終わりにルールを追記する。
# -I 値として指定した位置にルールを挿入する。指定無しならチェーンの最上部にルールを置く。
###########################################################################################
echo "Refreshing rules of IPTABLES.........."
# 内部ネットワークアドレス設定(環境によって変える)
LOCALNET=192.168.0.0/16
# 設定ファイルの場所(iptables-persistentが必要)
IPTABLES_CONFIG=/etc/iptables/rules.v4
# 国別コードの取得とファイルの存在確認
IP_LIST=/root/COUNTRY_CODE/cidr.txt
if [ -z "$IP_LIST" ]; then
echo "Error: Can't find country_code_list. Refreshing was canceled."
echo "Please create/execute /etc/cron.monthly/dl_iplist before."
exit 1
fi
if [ ! -e $IP_LIST ];then
bash /etc/cron.monthly/dl_iplist
fi
# 現在のルールファイルを削除
rm -f $IPTABLES_CONFIG
# デフォルトルール(以降のルールにマッチしなかった場合に適用するルール)設定
echo "*filter" >> $IPTABLES_CONFIG
echo ":INPUT DROP [0:0]" >> $IPTABLES_CONFIG # 受信はすべて破棄
echo ":FORWARD DROP [0:0]" >> $IPTABLES_CONFIG # 通過はすべて破棄
echo ":OUTPUT ACCEPT [0:0]" >> $IPTABLES_CONFIG # 送信はすべて許可
echo ":ACCEPT_COUNTRY - [0:0]" >> $IPTABLES_CONFIG # 指定した国からのアクセスを許可
echo ":DROP_COUNTRY - [0:0]" >> $IPTABLES_CONFIG # 指定した国からのアクセスを破棄
echo ":LOG_PINGDEATH - [0:0]" >> $IPTABLES_CONFIG # Ping of Death攻撃はログを記録して破棄
# 自ホストからのアクセスをすべて許可
echo "-A INPUT -i lo -j ACCEPT" >> $IPTABLES_CONFIG
# 内部からのアクセスをすべて許可
echo "-A INPUT -s $LOCALNET -j ACCEPT" >> $IPTABLES_CONFIG
# 内部から行ったアクセスに対する外部からの返答アクセスを許可
echo "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT" >> $IPTABLES_CONFIG
# SYN Cookiesを有効にする
# TCP SYN Flood攻撃対策
sysctl -w net.ipv4.tcp_syncookies=1 > /dev/null
sed -i '/net.ipv4.tcp_syncookies/d' /etc/sysctl.conf
echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf
# ブロードキャストアドレス宛pingには応答しない
# Smurf攻撃対策
sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1 > /dev/null
sed -i '/net.ipv4.icmp_echo_ignore_broadcasts/d' /etc/sysctl.conf
echo "net.ipv4.icmp_echo_ignore_broadcasts=1" >> /etc/sysctl.conf
# ICMP Redirectパケットは拒否
sed -i '/net.ipv4.conf.*.accept_redirects/d' /etc/sysctl.conf
for dev in `ls /proc/sys/net/ipv4/conf/`
do
sysctl -w net.ipv4.conf.$dev.accept_redirects=0 > /dev/null
echo "net.ipv4.conf.$dev.accept_redirects=0" >> /etc/sysctl.conf
done
# Source Routedパケットは拒否
sed -i '/net.ipv4.conf.*.accept_source_route/d' /etc/sysctl.conf
for dev in `ls /proc/sys/net/ipv4/conf/`
do
sysctl -w net.ipv4.conf.$dev.accept_source_route=0 > /dev/null
echo "net.ipv4.conf.$dev.accept_source_route=0" >> /etc/sysctl.conf
done
# フラグメント化されたパケットはログを記録して破棄
echo "-A INPUT -f -j LOG --log-prefix \"[IPTABLES FRAGMENT] : \"" >> $IPTABLES_CONFIG
echo "-A INPUT -f -j DROP" >> $IPTABLES_CONFIG
# 外部とのNetBIOS関連のアクセスはログを記録せずに破棄
# 不要ログ記録防止
echo "-A INPUT ! -s $LOCALNET -p tcp -m multiport --dports 135,137,138,139,445 -j DROP" >> $IPTABLES_CONFIG
echo "-A INPUT ! -s $LOCALNET -p udp -m multiport --dports 135,137,138,139,445 -j DROP" >> $IPTABLES_CONFIG
echo "-A OUTPUT ! -d $LOCALNET -p tcp -m multiport --sports 135,137,138,139,445 -j DROP" >> $IPTABLES_CONFIG
echo "-A OUTPUT ! -d $LOCALNET -p udp -m multiport --sports 135,137,138,139,445 -j DROP" >> $IPTABLES_CONFIG
# 1秒間に4回を超えるpingはログを記録して破棄
# Ping of Death攻撃対策
echo "-A LOG_PINGDEATH -m limit --limit 1/s --limit-burst 4 -j ACCEPT" >> $IPTABLES_CONFIG
echo "-A LOG_PINGDEATH -j LOG --log-prefix \"[IPTABLES PINGDEATH] : \"" >> $IPTABLES_CONFIG
echo "-A LOG_PINGDEATH -j DROP" >> $IPTABLES_CONFIG
echo "-A INPUT -p icmp --icmp-type echo-request -j LOG_PINGDEATH" >> $IPTABLES_CONFIG
# 全ホスト(ブロードキャストアドレス、マルチキャストアドレス)宛パケットはログを記録せずに破棄
# ※不要ログ記録防止
echo "-A INPUT -d 255.255.255.255 -j DROP" >> $IPTABLES_CONFIG
echo "-A INPUT -d 224.0.0.1 -j DROP" >> $IPTABLES_CONFIG
# 113番ポート(IDENT)へのアクセスには拒否応答
# ※メールサーバ等のレスポンス低下防止
echo "-A INPUT -p tcp --dport 113 -j REJECT --reject-with tcp-reset" >> $IPTABLES_CONFIG
# 80番ポート(http)に対して1秒に5回を超えるリクエストは破棄(DoS対策)
echo "-A INPUT -p tcp -m state --state NEW --dport 80 -m hashlimit --hashlimit-name t_http --hashlimit 1/s --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-htable-expire 900000 -j ACCEPT" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp -m state --state NEW --dport 80 -j DROP" >> $IPTABLES_CONFIG
# 25番ポート(smtp)に対して1分に8回を超えるリクエストは破棄(DoS対策)
echo "-A INPUT -p tcp -m state --state NEW --dport 25 -m hashlimit --hashlimit-name t_smtp --hashlimit 1/m --hashlimit-burst 8 --hashlimit-mode srcip --hashlimit-htable-expire 900000 -j ACCEPT" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp -m state --state NEW --dport 25 -j DROP" >> $IPTABLES_CONFIG
# 110番ポート(pop3)に対して3分に35回を超えるリクエストは破棄(DoS対策)
echo "-A INPUT -p tcp -m state --state NEW --dport 110 -m hashlimit --hashlimit-name t_pop --hashlimit 3/m --hashlimit-burst 35 --hashlimit-mode srcip --hashlimit-htable-expire 18000000 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp -m state --state NEW --dport 110 -j DROP" >> $IPTABLES_CONFIG
# 143番ポート(imap)に対して3分に35回を超えるリクエストは破棄(DoS対策)
echo "-A INPUT -p tcp -m state --state NEW --dport 143 -m hashlimit --hashlimit-name t_imap --hashlimit 3/m --hashlimit-burst 35 --hashlimit-mode srcip --hashlimit-htable-expire 18000000 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp -m state --state NEW --dport 143 -j DROP" >> $IPTABLES_CONFIG
# 443番ポート(https)に対して1秒に5回を超えるリクエストは破棄(DoS対策)
echo "-A INPUT -p tcp -m state --state NEW --dport 443 -m hashlimit --hashlimit-name t_https --hashlimit 1/s --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-htable-expire 900000 -j ACCEPT" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp -m state --state NEW --dport 443 -j DROP" >> $IPTABLES_CONFIG
# 465番ポート(smtps)に対して1分に8回を超えるリクエストは破棄(DoS対策)
echo "-A INPUT -p tcp -m state --state NEW --dport 465 -m hashlimit --hashlimit-name t_smtp --hashlimit 1/m --hashlimit-burst 8 --hashlimit-mode srcip --hashlimit-htable-expire 900000 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp -m state --state NEW --dport 465 -j DROP" >> $IPTABLES_CONFIG
# 587番ポート(submission)に対して1分に8回を超えるリクエストは破棄(DoS対策)
echo "-A INPUT -p tcp -m state --state NEW --dport 587 -m hashlimit --hashlimit-name t_smtp --hashlimit 1/m --hashlimit-burst 8 --hashlimit-mode srcip --hashlimit-htable-expire 900000 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp -m state --state NEW --dport 587 -j DROP" >> $IPTABLES_CONFIG
# 993番ポート(imaps)に対して3分に35回を超えるリクエストは破棄(DoS対策)
echo "-A INPUT -p tcp -m state --state NEW --dport 993 -m hashlimit --hashlimit-name t_imaps --hashlimit 3/m --hashlimit-burst 35 --hashlimit-mode srcip --hashlimit-htable-expire 18000000 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp -m state --state NEW --dport 993 -j DROP" >> $IPTABLES_CONFIG
# 995番ポート(pop3s)に対して3分に35回を超えるリクエストは破棄(DoS対策)
echo "-A INPUT -p tcp -m state --state NEW --dport 995 -m hashlimit --hashlimit-name t_pop3s --hashlimit 3/m --hashlimit-burst 35 --hashlimit-mode srcip --hashlimit-htable-expire 900000 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp -m state --state NEW --dport 995 -j DROP" >> $IPTABLES_CONFIG
# ACCEPT_COUNTRY_MAKE関数定義
# 指定された国のIPアドレスからのアクセスを許可するユーザ定義チェイン作成
ACCEPT_COUNTRY_MAKE(){
for addr in `cat $IP_LIST | grep ^$1 | awk '{print $2}'`
do
echo "-A ACCEPT_COUNTRY -s $addr -j ACCEPT" >> $IPTABLES_CONFIG
done
}
# DROP_COUNTRY_MAKE関数定義
# 指定された国のIPアドレスからのアクセスを破棄するユーザ定義チェイン作成
DROP_COUNTRY_MAKE(){
for addr in `cat $IP_LIST | grep ^$1 | awk '{print $2}'`
do
echo "-A DROP_COUNTRY -s $addr -m limit --limit 1/s -j LOG --log-prefix \"[IPTABLES DENY_COUNTRY] : \"" >> $IPTABLES_CONFIG
echo "-A DROP_COUNTRY -s $addr -j DROP" >> $IPTABLES_CONFIG
done
}
# 日本からのアクセスを許可するユーザ定義チェインACCEPT_COUNTRY作成
ACCEPT_COUNTRY_MAKE JP
# 不正アクセスの多い海外からのアクセスをログを記録して破棄
DROP_COUNTRY_MAKE BR
DROP_COUNTRY_MAKE ID
DROP_COUNTRY_MAKE TW
DROP_COUNTRY_MAKE CN
DROP_COUNTRY_MAKE KR
DROP_COUNTRY_MAKE RU
DROP_COUNTRY_MAKE KP
DROP_COUNTRY_MAKE HK
DROP_COUNTRY_MAKE VN
DROP_COUNTRY_MAKE IN
DROP_COUNTRY_MAKE IR
DROP_COUNTRY_MAKE NL
DROP_COUNTRY_MAKE UA
DROP_COUNTRY_MAKE SG
DROP_COUNTRY_MAKE DE
DROP_COUNTRY_MAKE RO
DROP_COUNTRY_MAKE BD
echo "-A INPUT -j DROP_COUNTRY" >> $IPTABLES_CONFIG
#----------------------------------------------------------#
# 各種サービスを公開する場合の設定(ここから) #
#----------------------------------------------------------#
# 外部からのTCP/UDP53番ポート(DNS)へのアクセスを許可
# 外部向けDNSサーバーを運用する場合のみ
#echo "-A INPUT -p tcp --dport 53 -j ACCEPT" >> $IPTABLES_CONFIG
#echo "-A INPUT -p udp --dport 53 -j ACCEPT" >> $IPTABLES_CONFIG
# 外部からのTCP80番ポート(HTTP)へのアクセスを許可
# 外部からのTCP443番ポート(HTTPS)へのアクセスを許可
# 証明書の自動更新に80番ポートを使う事がある
echo "-A INPUT -p tcp --dport 80 -j ACCEPT" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp --dport 443 -j ACCEPT" >> $IPTABLES_CONFIG
# 外部からのTCP25番ポート(SMTP)へのアクセスを許可
# 外部からのTCP465番ポート(SMTPS)へのアクセスを日本からのみ許可
# 外部からのTCP587番ポート(Submission)へのアクセスを日本からのみ許可
# SMTPサーバーを公開する場合のみ
echo "-A INPUT -p tcp --dport 25 -j ACCEPT" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp --dport 465 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp --dport 587 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
# 外部からのTCP110番ポート(POP3)へのアクセスを日本からのみ許可
# 外部からのTCP995番ポート(POP3S)へのアクセスを日本からのみ許可
# POP3サーバーを公開する場合のみ
echo "-A INPUT -p tcp --dport 110 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp --dport 995 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
# 外部からのTCP143番ポート(IMAP)へのアクセスを日本からのみ許可
# 外部からのTCP993番ポート(IMAPS)へのアクセスを日本からのみ許可
# IMAPサーバーを公開する場合のみ
echo "-A INPUT -p tcp --dport 143 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
echo "-A INPUT -p tcp --dport 993 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
# 外部からのUDP1194番ポート(OpenVPN)へのアクセスを日本からのみ許可
# OpenVPNサーバーを公開する場合のみ
#echo "-A INPUT -p udp --dport 1194 -j ACCEPT_COUNTRY" >> $IPTABLES_CONFIG
# VPNインタフェース用ファイアウォール設定
# OpenVPNサーバーを公開する場合のみ
#[ -f /etc/openvpn/openvpn-startup ] && /etc/openvpn/openvpn-startup
#----------------------------------------------------------#
# 各種サービスを公開する場合の設定(ここまで) #
#----------------------------------------------------------#
# 拒否IPアドレスからのアクセスはログを記録せずに破棄
# 拒否IPアドレスは/root/deny_ipに1行ごとに記述しておくこと
# (/root/deny_ipがなければなにもしない)
if [ -s /root/deny_ip ]; then
for ip in `cat /root/deny_ip`
do
echo "-I INPUT -s $ip -j DROP" >> $IPTABLES_CONFIG
done
fi
# 上記のルールにマッチしなかったアクセスはログを記録して破棄
echo "-A INPUT -m limit --limit 1/s -j LOG --log-prefix \"[IPTABLES INPUT] : \"" >> $IPTABLES_CONFIG
echo "-A INPUT -j DROP" >> $IPTABLES_CONFIG
echo "-A FORWARD -m limit --limit 1/s -j LOG --log-prefix \"[IPTABLES FORWARD] : \"" >> $IPTABLES_CONFIG
echo "-A FORWARD -j DROP" >> $IPTABLES_CONFIG
# ファイアウォール設定終了
echo "COMMIT" >> $IPTABLES_CONFIG
echo "Refreshing /etc/iptables/rules.v4 done."
設定を反映させるスクリプトを書く
vi iptables.sh
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin
# makerules.sh を先に実行してルールを作成する。
# 設定を反映するだけのスクリプトです。
echo -e "\n"
echo -e " ############### YOU ARE TRYING TO RELOAD IPTABLES ####################\n"
echo -e " 注意:makerules.shを先に実行してルールを作成しておいてください。"
echo -e " IPTABLESの設定を再読み込みします。よろしいですか?\n"
echo -e " WARNING: You have to execute makerules.sh before."
echo -e " Are you ready to reload configure of IPTABLES? \n"
read -p " Type y or n :" yn
case $yn in
[yY]*)
echo -e " Reloading iptables.... wait a few mins."
# 現在の設定をクリア
iptables -F
iptables -X
# 設定をリロード
bash netfilter-persistent reload
# 後ほど構築するids(atcheck.sh)で登録されたipを再度設定。
# 構築した後にコメントを外す。
#bash /root/atcheck.sh
echo -e " IPTABLES reloading done.\n"
;;
*)
echo -e "\n Your operation is cancelled."
exit
;;
esac
ルールだけを作り直したい場合はmakerules.sh
を実行、作ったルールを反映させたいときはiptables.sh
を実行する。
作成した2つのスクリプトは次に続くdl_iplist
を記述してから実行する。
自動でグローバルIPを取得して定期的に設定を見直す
国別のIPリスト(cidr形式)を自動取得するスクリプトを作成。ダウンロード先のサイトは接続制限があるので、短時間に何度も実行しない。何度もやるとファイルが空になったりするよ!
mkdir /root/COUNTRY_CODE
vi /etc/cron.monthly/dl_iplist
ダウンロードできたかどうか、ダウンロードしたファイルが空になっていないかどうかを確認して一覧を保存しています。保存先は/root/COUNTRY_CODE/cidr.txt
。スクリプト中のxxxx
の部分は各自の環境に合わせて変更。
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
#############################################################
# Automatic download script for Country Code as cidr list. #
#############################################################
MYDIR=/root/COUNTRY_CODE
rm -f $MYDIR/cidr.txt.old
if [ -e $MYDIR/cidr.txt ];then
mv $MYDIR/cidr.txt $MYDIR/cidr.txt.old
fi
# 一覧のダウンロード。
wget -q -O $MYDIR/cidr.txt.gz http://nami.jp/ipv4bycc/cidr.txt.gz \
--user-agent='xxxxx@xxxxx.jp' --referer='Thanks from xxxxx.jp'
if [ $? -ne 0 ]; then
echo "Couldn't download Country Codes list from nami.jp." | mail -s 'cron dl_iplist was failed' root
cp $MYDIR/cidr.txt.old $MYDIR/cidr.txt
exit
else
gunzip -c $MYDIR/cidr.txt.gz > $MYDIR/cidr.txt
rm -f $MYDIR/cidr.txt.gz
fi
if [ -s $MYDIR/cidr.txt ];then
rm -f $MYDIR/cidr.txt.old
bash /root/makerules.sh > /dev/null 2>&1
# すぐ適応させる場合は以下のコメントを外す。
# echo "y" | bash /root/iptables.sh
# 更新時に絶賛稼働中だったら困るじゃん!って心配な人は以下で通知だけ。
# 次にログインしたときに iptables.sh を手動で実行するか、cronで予定実行するかしてね!
echo "Country code list updated. Please reload iptables or wait for next restart system." \
| mail -s "Country codes have been updated. From XXXXX Sever."
else
rm -f $MYDIR/cidr.txt
mv $MYDIR/cidr.txt.old $MYDIR/cidr.txt
fi
exit 0
ルール作成と設定反映
bash /etc/cron.monthly/dl_iplist
bash makerules.sh
bash iptables.sh
ASNからIPを調べて拒否する
サーバーはアメリカにあるけど、他国の企業のVPSです、というパターンがある。例えばCNを拒否していても、アメリカのサーバー経由(IPアドレス)でアクセスしてくる。おそらくサービス提供もその国の言語で提供しているだろうから、実は国まるごとのフィルタも気休め程度。
そんなパターンのIPアドレスを調べるにはASNを調べる。
COUNTRY_CODE
ディレクトリ内にASNのテキストを作成してフィルタを追加するには、以下のコードをmakeules.sh
のDROP_COUNTRY_MAKE
の後くらいに追記する。
# 例えばUcloud VPS を拒否。香港のVPSでアメリカにあるサーバーのIP。
if [ -s /root/COUNTRY_CODE/ucloud.txt ]; then
for ip in `cat /root/COUNTRY_CODE/ucloud.txt | awk '{print $1}' | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.'`
do
if [ -n $ip ]; then
echo "-I INPUT -s $ip -j DROP" >> $IPTABLES_CONFIG
fi
done
fi
COUNTRY_CODE
内にucloud.txtを記載。
# Ucloud Information Technology HK Limited. Written only server IPs beeing at US.
# 2022.8.10
# information from https://ipinfo.io/AS135377
107.150.112.0/24 ZENLA-1 256
107.150.117.0/24 ZENLA-1 256
ここらへんはイタチごっこ。他にもDegital Ocean
とかDelis LLC
とか、アクセス可能な国で不正アクセスチャレンジが多いサーバーはASNからIPを調べてまるごとブロックしていくのも一手。正規の企業が利用していることもあるので、それぞれの環境でよーく調査、影響を考慮する。自動化できれば良いんだけどなぁ。
とにかく相手にお金と時間がかかるようにして、運用に支障の出ない強固なファイヤーウォール構築を目指す。
Gitリポジトリ
動的なファイヤーウォールを構築する
次の記事でswatchによる動的なファイヤウォールを構築します。
参考サイト