前回までの作業で、mod_security2 のApacheへの組み込み、および
その設定ファイル集である Core Rule Set の準備が完了しました。
crsでは、目的ごとに、それぞれ設定ファイルが分けて作られています。
たぶん、SQLインジェクション攻撃からWebアプリケーションを守る
modsecurity_crs_41_sql_injection_attacks.conf
たぶん、クロスサイトスクリプティング攻撃からWebアプリケーションを守る
modsecurity_crs_41_xss_attacks.conf
ブルートフォース攻撃から防衛するための
modsecurity_crs_11_brute_force.conf
…みたいな感じで、いろいろな設定ファイルが用意されています。
今回はこれらの中から、
modsecurity_crs_11_slow_dos_protection.conf
だけを使用し、
『slow DoS』攻撃から防衛する設定 だけ を行います。
今回使用するのは experimental_rules ディレクトリに入っている
crs/experimental_rules/modsecurity_crs_11_slow_dos_protection.conf
という設定ファイルです。
experimental = 実験的 ですから、まだ完成形とはいえない、問題もある設定なのかもしれない…
そう考えながら、このファイルを activated_rules ディレクトリにコピーします。
cp crs/experimental_rules/modsecurity_crs_11_slow_dos_protection.conf crs/activated_rules/
そして、httpd を再起動します。
service httpd restart
これにて、設定は完了しました。
さっそく slowhttptest を使って攻撃してみてください。
今度はサーバが停止しません。成功しましたね。
めでたしめでたし。
おつかれさまでした。
…と思ったけどそれでもサーバダウンする!!
ではどうすればいいの?
まずは、今回使用した設定ファイルの中身を見てみましょう。
いったいどんなことをしているのでしょう?
コメント欄を省略すると… modsecurity_crs_11_slow_dos_protection.conf は次のようになっていました。
SecReadStateLimit 100 <IfModule reqtimeout_module> RequestReadTimeout body=30 </IfModule> SecRule RESPONSE_STATUS "@streq 408" "phase:5,id:'981051',t:none,nolog,pass,setvar:ip.slow_dos_counter=+1,expirevar:ip.slow_dos_counter=60" SecRule IP:SLOW_DOS_COUNTER "@gt 5" "phase:1,id:'981052',t:none,log,drop,msg:'Client Connection Dropped due to high # of slow DoS alerts'"
設定のひとつめ SecReadStateLimit には解説があります。
http://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#SecReadStateLimit
解説にはだいたいこう書いてあって:
- Slowlorisのようなタイプの攻撃に対して効果的
- HTTP BODYの低速送信攻撃には効果がないから、それは mod_reqtimeout を使ってね
設定内容の2項目(RequestReadTimeout body=30)に、それが書かれています。
最後の SecRule で始まる2行。
僕もよくわかっていませんが、おそらくは、タイムアウトの発生を、送信元IPアドレスごとにカウントして、
閾値を超えた場合に、そこからのアクセスを拒否するようになっているものと思われます。
つまり
- 「SecReadStateLimit」「RequestReadTimeout」でタイムアウトを発生させる。
- 同じIPから一杯タイムアウトになる要求が来てたら、そのIPからの接続を拒否する。
ということをしている、とわかりました。
概要がわかったところで、今度は詳細を読んでみます。
すると、割と簡単なところで問題点に気がつきました。
1項目の
「SecReadStateLimit 100」
の意味。
「ひとつのIPアドレスからのお客さんで、同時にSERVER_BUSY_READ状態になっていい数を制限する」
とありました。
つまり、100接続を許しているので、100接続をいちど実現させてあげないことには、
残りの設定は機能しないため、攻撃から防衛できないことになります。
そういえば、と思い出して、ここで自分のところの apache の設定ファイル httpd.conf を読んでみると…
StartServers 40 MinSpareServers 40 MaxSpareServers 40 ServerLimit 40 MaxClients 40
そもそも40しか接続できなくなっています。
ということは、
「SecReadStateLimit 100」
はどうやっても発動しません。40までしか増えないんだから。
これではダメですね。
ってことで、modsecurity_crs_11_slow_dos_protection.conf を次のように変更してみました。
SecReadStateLimit 20 SecWriteStateLimit 20 <IfModule reqtimeout_module> RequestReadTimeout body=20 </IfModule> SecRule RESPONSE_STATUS "@streq 408" "phase:5,id:'981051',t:none,nolog,pass,setvar:ip.slow_dos_counter=+1,expirevar:ip.slow_dos_counter=60" SecRule IP:SLOW_DOS_COUNTER "@gt 5" "phase:1,id:'981052',t:none,log,drop,msg:'Client Connection Dropped due to high # of slow DoS alerts'"
今度は20本の SERVER_BUSY_READ 状態の接続があれば発動するようになりました。
なったはずです。
こんどこそ!
ということで、apacheを再起動。
service httpd restart
そして slowhttptest で攻撃。
今度は…
攻撃開始から1秒から2秒後までは、重くて応答なし。
しかし3秒後以降は、負荷なし、ノーダメージでサービス継続状態になりました!
大成功と相成りました。
結論としては
・modsecurity_crs_11_slow_dos_protection.conf は slowhttptest による攻撃に対して有効。
・Apacheの、接続数などの設定値の大きさに応じて、modsecurity_crs_11_slow_dos_protection.conf 内の数値も書き換えて調整する必要がある。
・SecReadStateLimit, SecWriteStateLimit の値は、httpd.conf の ServerLimit や MaxClients の値より(たぶん、充分に)小さくする必要がある。
最後に、どの方法だとどんな攻撃を防げたかを表にしてみました。
防衛の種類 | slowhttptest攻撃パターン(※3) | 効果 | Apache+PHP(WordPress) | Apache+htmlファイル1個 | ||
攻撃中にブラウザで見に行って正常に表示されるかどうか | メモリ消費量 | 攻撃中にブラウザで見に行って正常に表示されるかどうか | メモリ消費量 | |||
ノーガード | H | × | なし | × | なし | |
B | × | 膨大 (※2) |
× | なし | ||
R | ○ | ○(※1) | なし | ○ | なし | |
X | × | なし | × | なし | ||
mod_antiloris を使用 | H | ○ | ○ | なし | ○ | なし |
B | × | 膨大 | × | なし | ||
R | ○ | ○ | なし | ○ | なし | |
X | × | なし | × | なし | ||
mod_security2 を使用 | H | ○ | ○ | なし | ○ | なし |
B | ○ | ○ | なし | ○ | なし | |
R | ○ | ○ | なし | ○ | なし | |
X | ○ | ○ | なし | ○ | なし |
(※1) Apacheの旧バージョン、2.2系では2.2.20およびそれ以前のバージョンでは脆弱性があったが、それ以降のバージョンのApacheでは、初期状態で既にこの(Range header DoS vulnerability – CVE-2011-3192)攻撃に耐性がある。
(※2) htmlや画像ファイルのダウンロード要求に対しては、コネクション数が増大しても、サーバメモリ消費量は限定的である。一方で、phpやcgiスクリプトに対しこの攻撃がなされると、同時に大量のプログラムが起動した状態になり、メモリ消費量が膨大になる。物理メモリを使い切るとシステムが大幅にスローダウンするため、この場合でも物理メモリを使い切らないように、プログラム、Apache、データベースのメモリ消費量関係の設定を控えめにする必要がある。
(※3) slowhttptestのオプション。H=slow down in Header section, B=slow down in message Body, R=Range header, X=slow read
最近のコメント