DoS対策としてEC2のapacheにmod_dosdetectorを入れる
AWSのEC2にApacheを入れて運用していると、どこからともなく大量のアクセスが来て、サーバーが高負荷になってしまいレスポンスが悪くなってお客さんからクレームが殺到…なんていう事態があるかと思います。
そのためにAWSではマネージドサービスの「AWS WAF(ウェブアプリケーションファイアウォール)」が用意されていたり、サーバーインストール型のパッケージだとfail2banが利用可能だったりするわけですが、残念ながら以下の欠点があります。
AWS WAFのDoS攻撃に対する欠点
AWS WAFのデメリットは、レートベース(Rate-based rule)のルールを設定する場合に、5分間で何回以上のリクエストがあったかを判断の基準にしないといけないため、1秒で100リクエストくるようなDoS攻撃への対処ができないことです。
大規模なサイトだと大量のサーバーで捌いているのでこのルールでも設定できるのかもしれませんが、中小規模のサーバー構成では(とくにDBへのリクエストが発生するようなURLの場合は)5分も耐えられないでしょう。
AWSにはここを改善してほしいですね。
fail2banのDoS攻撃に対する欠点
fail2banはapacheサーバーのアクセスログを直接見るため、AWS WAFにあったようなレートベースのブロックルールが細かく設定できるので、一見問題がないかのように思えます。
しかし、fail2banはpythonプログラムで動いており、apacheログの監視をして、ログとブロックルール(jailと言います)が一致したらfirewallにルールを追加する、という手順を踏むため、例えば1秒で100リクエストくるような攻撃があった場合、攻撃元のIPをブロックし始めている間にその大量の攻撃リクエストはapacheにどんどん溜まっていくわけです。
私も最初は「あれ?ブロックしたはずなのになんでこれだけリクエストがapacheログに記録されているんだ?」と思ったのですが、原因はそのプロセスの複雑さによる対処の遅延が原因だったわけです。
そのため、DB(AWSだとRDSなど)にもリクエストするようなURLに対するDoS攻撃だった場合、DBサーバーに大量のリクエストが飛んでしまい、DBが高負荷になってしまってapacheにレスポンスが返ってこない事態に陥ります。
mod_dosdetectorで解決
これらの問題を解決してくれたのが、apacheモジュールであるmod_dosdetectorです。
fail2banほど細かい設定はできませんが、逆にいうとそれだけシンプルで素早い対処が可能なため、URLリクエストが届いてもルールに一致したら受け付けないようにできます。
インストール方法
まず、apxsコマンド、gccコマンドが使えるようにパッケージを追加でインストールします。
sudo yum install -y httpd-devel gcc
次にapacheのrewriteモジュールが有効になっているかどうかを確認。以下のようになっていればOKです。
sudo httpd -M | grep rewrite
Syntax OK
rewrite_module (shared)
次にmod_dosdetectorのソースをダウンロード。
今回、オリジナルのmod_dosdetectorではなく、いろいろとバージョンアップされたmod_dosdetector_syslogを導入します。
理由としては、DoSIgnoreContentTypeで画像等を除外する設定がうまく動かなかったのと、画像等にキャッシュを効かせて304を返す場合に設定が無視されてしまうためでした。
cd /usr/local/src
sudo git clone https://github.com/gure-suzuki/mod_dosdetector_syslog.git
Cloning into 'mod_dosdetector_syslog'...
remote: Enumerating objects: 113, done.
remote: Total 113 (delta 0), reused 0 (delta 0), pack-reused 113
Receiving objects: 100% (113/113), 42.78 KiB | 21.39 MiB/s, done.
Resolving deltas: 100% (60/60), done.
このソースのままだと、私の環境ではapxsコマンドのパスが/usr/sbin/apxsだったので、ソースを編集しておきます。
-APXS=/usr/local/sbin/apxs
+APXS=/usr/sbin/apxs
修正できたら保存してインストールします。
cd mod_dosdetector_syslog
sudo make install
...(インストールログが表示されます)
chmod 755 /usr/lib64/httpd/modules/mod_dosdetector_syslog.so
[activating module `dosdetector_syslog' in /etc/httpd/conf/httpd.conf]
mod_dosdetector_syslogインストール後の設定
設定は以下のような感じで運用しています。
かんたんに説明すると、まず画像やCSS、JSファイルやフォントファイルなどは環境変数で「NoCheckDoS」フラグを立てて、DoSDetectionの部分でDoS測定の対象外になるようにしています。
あとは、3秒間で12リクエストあったら1分間BANするように設定します。
<IfModule mod_dosdetector_syslog.c>
SetEnvIf Request_URI "\.(gif|jpe?g|ico|js|css|png|woff2?)" NoCheckDoS
DoSDetection !NoCheckDoS
DoSPeriod 3
DoSThreshold 12
DoSHardThreshold 12
DoSBanPeriod 60
DoSTableSize 100
DoSForwarded on
</IfModule>
設定したら一度apacheを再起動(restart)または再読み込み(reload)してくださいね。
最後に、DOCUMENT_ROOTの.htaccessにリライトルールを追加します。
# for DoS attack
RewriteEngine On
RewriteCond %{ENV:SuspectDoS} .+ [OR]
RewriteCond %{ENV:SuspectHardDoS} .+
RewriteCond %{REMOTE_ADDR} !^(10\.[0-9]+\.[0-9]\.[0-9])$
RewriteCond %{REMOTE_ADDR} !^(172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]+\.[0-9]+)$
RewriteCond %{REMOTE_ADDR} !^(192\.168\.[0-9]+\.[0-9]+)$
RewriteRule .* - [R=503,L]
欠点としてはEC2サーバーそれぞれにインストール&設定されていないといけないというところですが、AMIを作ってオートスケーリング設定すれば大丈夫なので、大きな問題ではないかなと思います。
2022-01-21