想定環境
CentOS 6 または 7
# rpm -q mod_security mod_security_crs
mod_security-2.7.3-5.el6.x86_64
mod_security_crs-2.2.6-3.el6.noarch
# rpm -q mod_security mod_security_crs
mod_security-2.9.2-1.el7.x86_64
mod_security_crs-2.2.9-1.el7.noarch
はじめに、導入方針など
- デフォルトでインストールされるルールでは、誤検知が発生するので、最小限のルールのみ有効にします。
- 現状、本番環境での初期導入時はSQLインジェクションとクロスサイトスクリプティングに関するルールのみ残し、他は無効にします。
- 最初は、検出オンリーモードで様子をみるのが良さそうです。
- 開発環境では全てのルールを有効にしてみるなど、いろいろ試してみてください。問題ないと確認できれば、本番環境で随時ルールを有効にしていきます。
- デフォルトではログ出力が多いので、ディスク容量に余裕のない環境では設定を調整してください。
- 本番環境での誤検知発生にそなえて、特定のURLでルールを無効にする方法を確認してください。
rpmパッケージの導入
epelリポジトリからrpmパッケージをインストールします。
# yum -y install mod_security mod_security_crs
mod_security
が Apache モジュール、mod_security_crs
がWAFのルールです。
初回導入時は、必ず設定を調整してから Apache を再起動して反映します。
# service httpd restart
設定変更時は、リロードで反映します。
# service httpd reload
SQLインジェクション・クロスサイトスクリプティングのルールを残し、その他は無効化する
デフォルトで読み込まれるWAFルールは、/etc/httpd/modsecurity.d/activated_rule
下にあります。
あらかじめバックアップを取得しておきましょう。
# cd /etc/httpd/modsecurity.d
# cp -rp activated_rule activated_rule.orig
# cd activated_rule
# ls -l
total 88
lrwxrwxrwx 1 root root 64 Jul 3 16:21 modsecurity_35_bad_robots.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_35_bad_robots.data
lrwxrwxrwx 1 root root 62 Jul 3 16:21 modsecurity_35_scanners.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_35_scanners.data
lrwxrwxrwx 1 root root 69 Jul 3 16:21 modsecurity_40_generic_attacks.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_40_generic_attacks.data
lrwxrwxrwx 1 root root 75 Jul 3 16:21 modsecurity_41_sql_injection_attacks.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_41_sql_injection_attacks.data
lrwxrwxrwx 1 root root 62 Jul 3 16:21 modsecurity_50_outbound.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_50_outbound.data
lrwxrwxrwx 1 root root 70 Jul 3 16:21 modsecurity_50_outbound_malware.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_50_outbound_malware.data
lrwxrwxrwx 1 root root 77 Jul 3 16:21 modsecurity_crs_20_protocol_violations.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_20_protocol_violations.conf
lrwxrwxrwx 1 root root 76 Jul 3 16:21 modsecurity_crs_21_protocol_anomalies.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_21_protocol_anomalies.conf
lrwxrwxrwx 1 root root 72 Jul 3 16:21 modsecurity_crs_23_request_limits.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_23_request_limits.conf
lrwxrwxrwx 1 root root 69 Jul 3 16:21 modsecurity_crs_30_http_policy.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_30_http_policy.conf
lrwxrwxrwx 1 root root 68 Jul 3 16:21 modsecurity_crs_35_bad_robots.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_35_bad_robots.conf
lrwxrwxrwx 1 root root 73 Jul 3 16:21 modsecurity_crs_40_generic_attacks.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_40_generic_attacks.conf
lrwxrwxrwx 1 root root 79 Jul 3 16:21 modsecurity_crs_41_sql_injection_attacks.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_41_sql_injection_attacks.conf
lrwxrwxrwx 1 root root 69 Jul 3 16:21 modsecurity_crs_41_xss_attacks.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_41_xss_attacks.conf
lrwxrwxrwx 1 root root 72 Jul 3 16:21 modsecurity_crs_42_tight_security.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_42_tight_security.conf
lrwxrwxrwx 1 root root 65 Jul 3 16:21 modsecurity_crs_45_trojans.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_45_trojans.conf
lrwxrwxrwx 1 root root 75 Jul 3 16:21 modsecurity_crs_47_common_exceptions.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_47_common_exceptions.conf
lrwxrwxrwx 1 root root 82 Jul 3 16:21 modsecurity_crs_48_local_exceptions.conf.example -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_48_local_exceptions.conf.example
lrwxrwxrwx 1 root root 74 Jul 3 16:21 modsecurity_crs_49_inbound_blocking.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_49_inbound_blocking.conf
lrwxrwxrwx 1 root root 66 Jul 3 16:21 modsecurity_crs_50_outbound.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_50_outbound.conf
lrwxrwxrwx 1 root root 75 Jul 3 16:21 modsecurity_crs_59_outbound_blocking.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_59_outbound_blocking.conf
lrwxrwxrwx 1 root root 69 Jul 3 16:21 modsecurity_crs_60_correlation.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_60_correlation.conf
拡張子 .data は、WAFルールが参照する定数などが定義されています。.conf がWAFルールの定義です。
SQLインジェクションmodsecurity_crs_41_sql_injection_attacks.conf
、クロスサイトスクリプティングmodsecurity_crs_41_xss_attacks.conf
を除いて、他のconfファイルを無効化します。
単純にシンボリックリンクを削除すると、yumアップデート時に再度有効になってしまうので、同名の空ファイルに置き換えます。
# find . -type l -name '*_crs_*' | grep -Ev 'sql|xss' | xargs -I% echo rm % \; touch % | bash
# ls -l
total 48
lrwxrwxrwx 1 root root 64 Jul 3 19:56 modsecurity_35_bad_robots.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_35_bad_robots.data
lrwxrwxrwx 1 root root 62 Jul 3 19:56 modsecurity_35_scanners.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_35_scanners.data
lrwxrwxrwx 1 root root 69 Jul 3 19:56 modsecurity_40_generic_attacks.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_40_generic_attacks.data
lrwxrwxrwx 1 root root 75 Jul 3 19:56 modsecurity_41_sql_injection_attacks.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_41_sql_injection_attacks.data
lrwxrwxrwx 1 root root 62 Jul 3 19:56 modsecurity_50_outbound.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_50_outbound.data
lrwxrwxrwx 1 root root 70 Jul 3 19:56 modsecurity_50_outbound_malware.data -> /usr/lib/modsecurity.d/base_rules/modsecurity_50_outbound_malware.data
-rw-r--r-- 1 root root 0 Jul 3 19:56 modsecurity_crs_20_protocol_violations.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_21_protocol_anomalies.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_23_request_limits.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_30_http_policy.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_35_bad_robots.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_40_generic_attacks.conf
lrwxrwxrwx 1 root root 79 Jul 3 19:56 modsecurity_crs_41_sql_injection_attacks.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_41_sql_injection_attacks.conf
lrwxrwxrwx 1 root root 69 Jul 3 19:56 modsecurity_crs_41_xss_attacks.conf -> /usr/lib/modsecurity.d/base_rules/modsecurity_crs_41_xss_attacks.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_42_tight_security.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_45_trojans.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_47_common_exceptions.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_48_local_exceptions.conf.example
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_49_inbound_blocking.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_50_outbound.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_59_outbound_blocking.conf
-rw-r--r-- 1 root root 0 Jul 3 19:54 modsecurity_crs_60_correlation.conf
無効にしたルールを有効にするには、シンボリックリンクを復活させてください。
# ln -sf /usr/lib/modsecurity.d/base_rules/modsecurity_crs_30_http_policy.conf .
バックアップから戻してもいいでしょう。
# cp -P ../activated_rules.orig/modsecurity_crs_30_http_policy.conf .
デフォルトに戻すには、バックアップした activated_rules に戻します。
# cd /etc/httpd/modsecurity.d
# mv activated_rule activated_rule.bk && mv activated_rule.orig activated_rule
誤って上書き・削除してしまったなどデフォルトの状態に戻したい場合は、上書きしたファイルを削除してから mod_security_crs
パッケージを再インストールします。
# rm /usr/lib/modsecurity.d/base_rules/*.conf
# yum reinstall mod_security_crs
ログ出力の調整
ログはデフォルトで Apache の error_log
と /var/log/httpd/modsec_audit.log
に出力されます。
modsec_audit.log
には、WAFに関係なく404を除く4xx,5xxエラーの詳細な情報が出力されるので、ログが短時間で肥大化しやすく、ディスク容量に余裕がない環境では危険です。
error_log
だけで検知された事は判断できるので、心配な環境では通常modsec_audit.log
への出力をオフにしておき、必要なタイミングでオンにすると良いでしょう。
SecAuditEngine Off
動作確認
SQLインジェクション検知の確認は、GETパラメータに?select+union
を付けてアクセスしてみて、403 Forbidden となるか確認します。
例: https://example.com/hoge/?union+select
error_log
の出力例を挙げます。
[Thu Jul 05 13:57:50 2018] [error] [client 192.168.0.100] ModSecurity: Access denied with code 403 (phase 2). Operator GE matched 3 at TX:sqli_select_statement_count. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"] [line "108"] [id "981317"] [rev "2"] [msg "SQL SELECT Statement Anomaly Detection Alert"] [data "Matched Data: Connection found within TX:sqli_select_statement_count: 3"] [ver "OWASP_CRS/2.2.6"] [maturity "8"] [accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] [tag "WASCTC/WASC-19"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE1"] [tag "PCI/6.5.2"] [hostname "example.com"] [uri "/hoge/"] [unique_id "Wz2lTsCoAa4AAEuRGe0AAAAA"]
WAFの検知があったかどうかは、文字列'ModSecurity: Access denied with code 'をgrepすれば調査できます。
# grep 'ModSecurity: Access denied with code ' /var/log/httpd/ssl_error_log
[name "value"]
の形式で検知情報が出力されています。適当に改行コードを入れます。
# grep 'ModSecurity: Access denied with code ' /var/log/httpd/ssl_error_log | tail -1 | sed 's/ \[/\n[/g'
[Thu Jul 05 13:57:50 2018]
[error]
[client 192.168.0.100] ModSecurity: Access denied with code 403 (phase 2). Operator GE matched 3 at TX:sqli_select_statement_count.
[file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"]
[line "108"]
[id "981317"]
[rev "2"]
[msg "SQL SELECT Statement Anomaly Detection Alert"]
[data "Matched Data: Connection found within TX:sqli_select_statement_count: 3"]
[ver "OWASP_CRS/2.2.6"]
[maturity "8"]
[accuracy "8"]
[tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"]
[tag "WASCTC/WASC-19"]
[tag "OWASP_TOP_10/A1"]
[tag "OWASP_AppSensor/CIE1"]
[tag "PCI/6.5.2"]
[hostname "example.com"]
[uri "/hoge/"]
[unique_id "Wz2lTsCoAa4AAEuRGe0AAAAA"]
ここで重要なのは、[id "981317"]
です。このルールを無効化する際に SecRuleRemoveById に指定します。
- id: 検知ルールID
- client: 検知されたクライアントIP
- file,line: 検知ルール定義場所
- msg: 検知ルールの概要
- data: 検知された問題のデータ
- hostname,uri: 検知されたURL
クロスサイトスクリプティングは、適当なテキストフォームにjavascript:alert(document.cookie)
を入力してサブミットし、403 Forbidden となるか確認します。
error_log
の出力例を挙げます。
[Thu Jul 05 14:55:33 2018] [error] [client 192.168.0.100] ModSecurity: Access denied with code 403 (phase 2). Pattern match "\\\\bdocument\\\\b\\\\s*\\\\.\\\\s*\\\\bcookie\\\\b" at ARGS:login_email. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_41_xss_attacks.conf"] [line "107"] [id "958001"] [rev "2"] [msg "Cross-site Scripting (XSS) Attack"] [data "Matched Data: document.cookie found within ARGS:login_email: javascript:alert(document.cookie)"] [severity "CRITICAL"] [ver "OWASP_CRS/2.2.6"] [maturity "8"] [accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/XSS"] [tag "WASCTC/WASC-8"] [tag "WASCTC/WASC-22"] [tag "OWASP_TOP_10/A2"] [tag "OWASP_AppSensor/IE1"] [tag "PCI/6.5.1"] [hostname "example.com"] [uri "/frontparts/login_check.php"] [unique_id "Wz2y1cCoAa4AAEuTGnsAAAAC"]
適当に改行コードを入れます。
# grep 'ModSecurity: Access denied with code ' /var/log/httpd/ssl_error_log | tail -1 | sed 's/ \[/\n[/g'
[Thu Jul 05 14:55:33 2018]
[error]
[client 192.168.0.100] ModSecurity: Access denied with code 403 (phase 2). Pattern match "\\\\bdocument\\\\b\\\\s*\\\\.\\\\s*\\\\bcookie\\\\b" at ARGS:login_email.
[file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_41_xss_attacks.conf"]
[line "107"]
[id "958001"]
[rev "2"]
[msg "Cross-site Scripting (XSS) Attack"]
[data "Matched Data: document.cookie found within ARGS:login_email: javascript:alert(document.cookie)"]
[severity "CRITICAL"]
[ver "OWASP_CRS/2.2.6"]
[maturity "8"]
[accuracy "8"]
[tag "OWASP_CRS/WEB_ATTACK/XSS"]
[tag "WASCTC/WASC-8"]
[tag "WASCTC/WASC-22"]
[tag "OWASP_TOP_10/A2"]
[tag "OWASP_AppSensor/IE1"]
[tag "PCI/6.5.1"]
[hostname "example.com"]
[uri "/frontparts/login_check.php"]
[unique_id "Wz2y1cCoAa4AAEuTGnsAAAAC"]
POSTパラメータ ARGS:login_email
に入力された値 javascript:alert(document.cookie)
が検知された事が読み取れます。
一行が長いので要約します。
# tail -1 /var/log/httpd/ssl_error_log | perl -nle '/^(?:.*? ){3}(.*?) .*id "(.*?)".*msg "(.*?)"/ && print "$1 $2 $3"'
WAFルールの無効化
利用者からの正当なリクエストを誤って検知してしまう偽陽性(false positive)が発生した場合、取り急ぎWAFルールを無効にして対応します。
正しい検知であり、アプリケーション側の問題であれば、修正して再度ルールを有効にします。
WAFに検知された場合、デフォルトでは 403 Forbidden となります。ベーシック認証やIP制限でも発生するので、WAFによるものかはログで確認します。
カスタムルールファイル
ルールを完全にオフにする場合は SecRuleEngine を、個別にオフにする場合は SecRuleRemoveById を指定します。.htaccess以外の任意のコンテキストに記述できます。バーチャルホスト以外のコンテキストに記述する場合は、下記 z_customrules.conf
を使用してください。SecRuleRemoveById は SecRule より後に評価される必要があるため、このファイルに記述するのが安全です。
原則、設定のカスタマイズは。下記ファイルを新規作成して記述してください。
- /etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_15_customrules.conf
- /etc/httpd/modsecurity.d/activated_rules/z_customrules.conf
modsecurity_crs_15_customrules.conf
は、定数初期化後かつルール定義前に読み込まれます。SecRuleより前に記述する必要があるSecDefaultActionやデフォルトルールより優先したいルールなどを記述します。
z_customrules.conf
は、ルール定義後に読み込まれます。
検出オンリーモード
検知しても遮断せず、ログのみ記録します。
SecRuleEngine DetectionOnly
WAF機能を完全オフ
最終手段として機能を完全オフにするには、次のように設定します。
SecRuleEngine Off
特定のURLでWAF機能を無効化
/admin
以下でWAFを無効化する設定は次の通りです。
<Directory /var/www/html/admin>
SecRuleEngine Off
</Directory>
URLにファイルが対応していないならば、Locationを使用します。
<Location /admin>
SecRuleEngine Off
</Location>
または、ルール個別に無効化する場合は、SecRuleRemoveById を記述します。引数のルールIDはスペース区切りで複数指定可能です。SecRuleRemoveById 自体を複数記述しても問題ありません。
<Directory /var/www/html/admin>
SecRuleRemoveById 981317 950001 959073 981255 981245
SecRuleRemoveById 950901 960024 981173 973300
</Directory>
バーチャルホスト単位でWAF機能を無効化
バーチャルホストコンテキストに、特定のURLでWAF機能を無効化する設定を記述します。
<VirtualHost *:443>
<IfModule mod_security2.c>
SecRuleEngine Off
</IfModule>
</VirtualHost>
mod_security.conf
の管理外のコンテキストに記述する場合は、モジュールをアップロードしてもエラーにならないよう IfModule を指定しましょう。
POSTサイズの調整
phpのpost_max_size
,upload_max_filesize
に合わせて、WAFのSecRequestBodyLimit
,SecRequestBodyNoFilesLimit
を調整する必要がありそうです。
https://qiita.com/70_10/items/3cfa76710c2321fa0d63