15
27

More than 5 years have passed since last update.

Apache WAF mod_security の導入

Posted at

想定環境

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への出力をオフにしておき、必要なタイミングでオンにすると良いでしょう。

/etc/httpd/conf.d/mod_security.conf
    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 は、ルール定義後に読み込まれます。

検出オンリーモード

検知しても遮断せず、ログのみ記録します。

/etc/httpd/conf.d/mod_security.conf
    SecRuleEngine DetectionOnly

WAF機能を完全オフ

最終手段として機能を完全オフにするには、次のように設定します。

/etc/httpd/conf.d/mod_security.conf
    SecRuleEngine Off

特定のURLでWAF機能を無効化

/admin 以下でWAFを無効化する設定は次の通りです。

z_customrules.conf
<Directory /var/www/html/admin>
    SecRuleEngine Off
</Directory>

URLにファイルが対応していないならば、Locationを使用します。

z_customrules.conf
<Location /admin>
    SecRuleEngine Off
</Location>

または、ルール個別に無効化する場合は、SecRuleRemoveById を記述します。引数のルールIDはスペース区切りで複数指定可能です。SecRuleRemoveById 自体を複数記述しても問題ありません。

z_customrules.conf
<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

参考情報

本家wiki
本家Reference Manual v2.x
本家Log Data Format

15
27
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
27