安装 Apache WAF mod_security
希望选择适合的环境
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 错误的详细信息。因此,在磁盘空间有限的环境中,日志很容易膨胀并且存在危险。
在只有错误日志的情况下可以判断是否被检测到,所以在担心的环境中,通常应将输出到modsec_audit.log的功能关闭,并在需要的时候打开。
SecAuditEngine Off
确认动作
我将尝试给您提供一种汉语的原生表达方式:
通过在GET参数中添加?select+union来进行测试,以确认检测到SQL注入攻击后是否会出现403 Forbidden的错误。
例如:https://example.com/hoge/?union+select
以下是错误日志的输出示例。
[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"]
可以通过grep字符串“ModSecurity: Access denied with code”来调查是否检测到了WAF。
# grep 'ModSecurity: Access denied with code ' /var/log/httpd/ssl_error_log
檢測資訊以 [名稱 “數值”] 的形式輸出,請適當插入換行符號。
# 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错误。下面是错误日志的示例输出。
跨站脚本攻击是指在适当的文本表单中输入javascript:alert(document.cookie),然后提交以验证是否会出现403 Forbidden错误。以下是错误日志的示例输出。
[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规则
如果错误地检测到用户的合法请求导致了虚假阳性的发生,我们会立刻禁用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功能。
在管理界面下,禁用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以确保模块上传不会引发错误。
调整帖子尺寸
根据php的post_max_size和upload_max_filesize,可能需要调整WAF的SecRequestBodyLimit和SecRequestBodyNoFilesLimit。
参考资料
本地维基百科
本地参考手册v2.x
本地日志数据格式