2012年1月4日水曜日

hashdos攻撃をmod_securityで防御する(CentOS+yum編)

このエントリでは、hashdos対策としてのmod_securityの導入と設定の方法を説明します。CentOS環境でyumによりApacheを導入しているサイトに対して、yumによりmod_securityを導入するというシナリオで説明します。

はじめに

既に当ブログで報告の通り、hashdosと呼ばれる攻撃手法が公表されています。HTTPリクエストのパラメータ名に対するハッシュ値を故意に同一にした(衝突させた)ものを多数(数万程度)送信することにより、Webサーバーを数分程度過負荷にできるというDoS攻撃手法です。まだhashdosによる攻撃事例は報告されていないようですが、既に攻撃コード(PoC)が公表されているため、いつ攻撃が起こっても不思議ではない状況です。
PHPも影響を受けるプラットフォームであり、PHP5.3.9で対処予定となっていますが、まだPHP5.3.9はリリースされていません。また、PHP5.3.9にすぐに移行できないWebサイトも多いことと思います。
PHP5.3.9に移行する以外の対処方法としては以下が考えられます。

  • HTTPリクエストボディ(POST変数)のサイズを数十KB以下に制限する
  • suhosinパッチを導入する。suhosin.post.max_vars(デフォルトは1000)をさらに制限するとなお良し

しかし、利用者に画像などのアップロード機能を提供しているWebサイトなど、上記を実行できないWebサイトも多いと予想します。

そこで対策案として浮上するのがWAFの導入です。WAFでパラメータ数の制限ができる場合、hashdos攻撃を有効に緩和できます。その例として、mod_securityをCentOSにyumで導入し、hashdos対策用に設定する例を紹介します。

CentOSにyumでmod_securityを導入する

CentOSのデフォルトのリポジトリでは、mod_securityはサポートされていません。このため、リポジトリを追加する必要があります。mod_securityの本家では、utterramblingsリポジトリを紹介していますが、CentOS6の対応が不明確でしたので、このエントリでは、CentOS5とCentOS6の両方に対応しているEPELリポジトリを使った導入方法を説明します。
まず、EPELリポジトリを設定します。
# rpm -Uvh http://download.fedora.redhat.com/pub/epel/6/i386/epel-release-6-5.noarch.rpm
CentOS5系とCentOS6および32ビットと64ビットでリポジトリ設定用のURLが異なるので、以下に示します。

CentOS6用
32ビット: http://download.fedora.redhat.com/pub/epel/6/i386/epel-release-6-5.noarch.rpm
64ビット: http://download.fedora.redhat.com/pub/epel/6/x86_64/epel-release-6-5.noarch.rpm

CentOS5用
32ビット: http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
64ビット: http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm

EPELリポジトリは普段使わないので、デフォルトでは使用しない設定にしておきます。/etc/yum.repos.d/epel.repo というファイルを編集して、[epel]グループの enabled=1 の行を enabled=0 に変更します。
[epel]
...
enabled=0
以上で準備ができましたので、yumでmod_securityをインストールします。先にEPELリポジトリを無効化しているので、以下のようにepelリポジトリを明示してインストールします。
# yum --enablerepo=epel install mod_security
これでmod_securityのインストールは終わりです。CRS(Core Rule Set)も同時にインストールされます。

mod_securityの動作確認

ここで、いったんmod_securityの動作確認をします。apacheを起動し、まずは正常系のアクセスを確認します。以下のURLはサンプルですので、既存コンテンツのURLを指定して下さい。
http://example.jp/index.php
次に、以下がmod_securityによりブロックされることを確認します。既存コンテンツの後ろに、「?union+select」をつけてアクセスします。
http://example.jp/index.php?union+select
403 Forbiddenのエラーが表示されれば、mod_securityが稼働していることになります。監査ログが /var/log/httpd/modsec_audit.log というファイル名で生成されているはずなので、確認しておきます。

ルールのカスタマイズ

次に、mod_securityのルールをカスタマイズします。上記の例(「union select」をブロックする)でもわかりますが、mod_securityに付属するCRS(Core Rule Set)は、やや過剰気味のチューニングになっています。mod_securityにじっくり付き合うのであれば、CRSをまじめにチューニングすればよいのですが、取り急ぎhashdos攻撃だけに対処するのであれば、思い切って他のルールは削除してしまいましょう。
そのためには、以下のようにします。/etc/httpd/conf.d/mod_security.conf を編集します。
Include modsecurity.d/*.conf
Include modsecurity.d/base_rules/*.conf
上記の部分を以下のように変更します(2行目のみ)。
Include modsecurity.d/*.conf
Include modsecurity.d/base_rules/modsecurity_crs_23_request_limits.conf
これにより、HTTPリクエストのサイズ制限のみのルールとなります。XSSやSQLインジェクションは防御できくなくなりますが、目をつぶることにします。

次に、同じファイルの以下の部分を修正します。
SecRequestBodyLimit 131072
リクエストボディの上限が131072バイト(128KB)に制限されています。これを以下のように変更します。
SecRequestBodyLimit 5242880
# 追加
SecRequestBodyNoFilesLimit 51200
上記例では、リクエストボディサイズを5Mバイトに増やし、新たにSecRequestBodyNoFilesLimitを50Kに設定しています。SecRequestBodyNoFilesLimitは、ファイルアップロード以外のPOSTサイズの制限(application/x-www-form-urlencoded形式の場合に有効)なので、hashdosに効果があります。5Mと50Kは、Webサイトの要件にあわせて調整して下さい。

次に、/etc/httpd/modsecurity.d/modsecurity_crs_10_config.conf というファイルを確認します。
## Maximum number of arguments in request limited
SecAction "phase:1,t:none,nolog,pass,setvar:tx.max_num_args=255"
tx.max_num_args=255 は、Webアプリケーションが受け取るパラメータの個数の上限値です。通常はこのままでよいと思いますが、パラメータ数が特に多いアプリケーションの場合は、この値を要件に合わせて増やします。

次に、/etc/httpd/modsecurity.d/base_rules/modsecurity_crs_23_request_limits.conf を修正します。
# Maximum number of arguments in request limited
SecRule &TX:MAX_NUM_ARGS "@eq 1" "chain,phase:2,t:none,pass,nolog,auditlog,msg:'Too ma
ny arguments in request',id:'960335',severity:'4',rev:'2.0.5'"
        SecRule &ARGS "@gt %{tx.max_num_args}" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:
tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.policy_score=+%{tx.notice_anomaly_s
core},setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"
このルールでパラメータ数をチェックしていますが、こままでは単なる警告でブロックしてくれません。このため、1番目のSecRuleにあるpassをdenyに修正しましょう。
SecRule &TX:MAX_NUM_ARGS "@eq 1" "chain,phase:2,t:none,deny,log,ctl:auditLogParts=ABDFGH,m
sg:'Too many arguments in request',id:'960335',severity:'2',rev:'2.0.5'"
上記では、「log,ctl:auditLogParts=ABDFGH」も追加しました。これは、ログを出力するが、POSTパラメータは出力しないと言う意味です。hashdosのPOSTパラメータは大きくなるので、ログを保存するとディスク容量が圧迫され、一種のDoS攻撃を受けることになるのでPOSTパラメータを除外しています。しかし、研究目的などでPOSTパラメータを保存したい場合は、「ctl:auditLogParts=ABDFGH」の部分を削除して下さい。

現実には、SecRequestBodyNoFilesLimitの方でブロックされるケースが大半だと思いますが、multipart/form-data形式(ファイルアップロードに使われる)でhashdos攻撃される可能性もあるので、上記は必要です。

*追記(2012/1/18)
Cookieによるhashdos攻撃が可能ですので、以下のルールを追加するとよいでしょう。

# Maximum number of Cookies
SecRule &TX:MAX_NUM_ARGS "@eq 1" "chain,phase:2,t:none,deny,log,ctl:auditLogParts=AFHZ,msg
:'Too many cookies in request',id:'960336',severity:'2',rev:'2.0.5'"
        SecRule &REQUEST_COOKIES "@gt %{tx.max_num_args}" "t:none,setvar:'tx.msg=%{rule.ms
g}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.policy_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"

Cookie数の上限はtx:max_num_argsを流用しています。255はCookie数の上限としては大きすぎますが、それほど問題にはならないと思います。しかし、さらに安全を期するには、30などとハードコーディングするか、Cookie数の最大値として別の変数を定義するとよいでしょう。
(追記終わり)


ルールのカスタマイズが終わったので、Apacheを再起動して下さい。
mod_securityの副作用の可能性があるので、一通りのチェックをしておくべきです。とくに、ファイルアップロードが影響を受けやすいので、ファイルアップロード機能がある場合(このエントリが想定しているサイトですが)は、必ずファイルアップロードが正常に動作することを確認してください。

まとめ

CentOSにyum環境でApacheを導入している環境向けに、mod_securityによるhashdos対策の方法を説明しました。
yumを使わないでソースからビルドしている場合や、Ubuntu向けの設定方法も予定しております。

[PR]
hashdosApacheKillerその他、Webサイトのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。

1 件のコメント:

  1. 2013/05/31(金) 現在、Core Rule Set (CRS) のインストールには別途 "yum install mod_security_crs" の実行が必要なようです。(本文中のように yum install mod_security だけでは CRS はインストールされません)

    返信削除

フォロワー