ModSecurity 默认安装后只是一个空壳引擎,它的检测能力完全取决于你加载的规则集。很多运维人员以为装上了就万事大吉,结果连最基础的 SQL 注入和跨站脚本攻击都拦不住,根本原因就是没有配置好 OWASP 核心规则集。在 Ubuntu 环境下,从规则集获取、加载到调优,每一步都有具体的操作细节,直接动手配置比看十篇理论文章都管用。

获取并部署 OWASP ModSecurity 核心规则集

Ubuntu 的默认仓库里 ModSecurity 和 CRS 是分开的,你需要单独拉取规则集。最稳妥的方式是从官方 GitHub 仓库克隆,这样能保证规则版本最新,而且后续更新也方便。

cd /etc/modsecurity
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo mv coreruleset crs
cd crs
sudo cp crs-setup.conf.example crs-setup.conf

克隆完成后,你会得到一个完整的规则集目录。crs-setup.conf 是规则集的全局配置文件,所有规则的行为调整都在这个文件里完成。不要直接修改 rules 目录下的规则文件,那样会导致后续更新时你的修改被覆盖。所有自定义配置都应该通过 crs-setup.conf 或者单独的排除规则文件来实现。

在 Apache 中加载规则集

规则文件下载好了,接下来要让 ModSecurity 知道去哪里加载它们。编辑 ModSecurity 的主配置文件,通常位于 /etc/modsecurity/modsecurity.conf。确保以下配置项存在且正确:

SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml application/json
SecAuditEngine RelevantOnly
SecAuditLog /var/log/modsecurity/audit.log
SecDebugLog /var/log/modsecurity/debug.log
SecDebugLogLevel 0

然后在 Apache 的 ModSecurity 加载配置中添加规则集引用。编辑 /etc/apache2/mods-enabled/security2.conf,在末尾加入:

IncludeOptional /etc/modsecurity/crs/crs-setup.conf
IncludeOptional /etc/modsecurity/crs/rules/*.conf

这里有个关键细节:crs-setup.conf 必须在所有规则文件之前加载,因为它定义了规则使用的各种阈值和开关。如果加载顺序反了,规则集启动时会报错或者使用默认参数运行,你的调优就白费了。

配置 crs-setup.conf 核心参数

crs-setup.conf 是整个规则集的大脑,里面有几个参数直接决定防护效果和误报率。打开这个文件,逐项检查以下配置。

异常评分阈值是最关键的参数。CRS 默认使用异常评分模式,每个匹配的规则都会累加分数,达到阈值就阻断请求。入站请求的默认阈值是 5,这个值对于生产环境来说偏严格,容易产生误报。建议初次部署时设为 10,运行一段时间观察日志后再逐步降低:

SecAction \
 "id:900110,\
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.inbound_anomaly_score_threshold=10,\
  setvar:tx.outbound_anomaly_score_threshold=4"

偏执级别决定了哪些规则组会被启用。CRS 有四个级别,从 1 到 4,数字越大规则越严格,误报也越多。级别 1 只包含基础防护规则,适合大多数生产环境。级别 2 增加了针对特定攻击向量的规则。级别 3 和 4 包含大量启发式检测,误报率很高,一般只用于安全审计场景。生产环境建议从级别 1 开始:

SecAction \
 "id:900120,\
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.paranoia_level=1"

还有一个容易被忽略的配置是请求体大小限制。ModSecurity 默认只检查前 128KB 的请求体,攻击者完全可以利用这个限制把恶意载荷藏在请求体后半部分。建议把这个值调大到 1MB,覆盖绝大多数正常请求:

SecRequestBodyLimit 1048576
SecRequestBodyNoFilesLimit 1048576
SQL 注入防护规则详解

OWASP CRS 中 SQL 注入防护的核心规则集中在 REQUEST-942-APPLICATION-ATTACK-SQLI.conf 文件里。这套规则通过正则匹配检测 SQL 关键字、函数调用和特殊字符组合。规则 942100 到 942190 覆盖了经典的 SQL 注入模式,包括联合查询注入、布尔盲注、时间盲注和堆叠查询。

举个例子,当攻击者尝试用单引号闭合语句进行注入时,规则 942130 会检测到 SQL 注释符和条件表达式的组合。如果请求中包含类似 "1' OR '1'='1" 的字符串,这条规则会触发并增加 5 分异常评分。配合前面设置的阈值 10,两次这样的尝试就会触发阻断。

对于 MySQL 特有的注入手法,规则 942140 专门检测 "INTO OUTFILE"、"INTO DUMPFILE" 这类文件写入操作。规则 942150 则针对 "SELECT ... INTO" 变量赋值注入。这些规则在实际攻防中非常有效,因为自动化扫描工具几乎都会使用这些经典手法。

跨站脚本攻击防护规则

XSS 防护规则在 REQUEST-941-APPLICATION-ATTACK-XSS.conf 中。这套规则比 SQL 注入规则更容易产生误报,因为很多正常的富文本内容会包含 HTML 标签和 JavaScript 事件属性。

规则 941100 到 941160 检测基础的 XSS 向量,包括 script 标签、事件处理器属性和 javascript 伪协议。规则 941170 到 941190 检测编码绕过尝试,比如 HTML 实体编码和 Unicode 编码的恶意字符。规则 941200 到 941210 则针对属性注入攻击,检测 onerror、onload 等事件属性。

实际部署中,XSS 规则最大的问题是误报。如果你的应用允许用户提交包含 HTML 的内容,比如论坛帖子或富文本编辑器,这些规则会频繁触发。解决办法不是直接关闭规则,而是针对特定 URL 或参数设置白名单。在 crs-setup.conf 同目录下创建一个排除规则文件:

# 文件: /etc/modsecurity/crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
SecRule REQUEST_URI "@beginsWith /api/editor/preview" \
 "id:10000,\
  phase:1,\
  pass,\
  nolog,\
  ctl:ruleRemoveById=941100-941210"

这样只对特定接口关闭 XSS 检测,其他入口的防护不受影响。精确的排除规则比全局降低阈值更安全。

远程文件包含和命令注入防护

远程文件包含攻击在规则集 REQUEST-930-APPLICATION-ATTACK-LFI.conf 中处理。规则 930100 检测路径遍历模式,比如 "../../../etc/passwd"。规则 930110 检测完整的文件路径访问。规则 930120 则针对 PHP 封装器的利用,比如 "php://input" 和 "expect://"。

命令注入防护在 REQUEST-932-APPLICATION-ATTACK-RCE.conf 中。这套规则检测系统命令关键字和管道符、反引号等 Shell 特殊字符。规则 932100 到 932115 覆盖了 Unix 命令注入,规则 932150 到 932160 针对 Windows 命令注入。实际攻击中常见的 "ping -c 10 127.0.0.1" 或者 "$(cat /etc/passwd)" 这类载荷都会被准确识别。

防护效果验证方法

配置完成后,不要直接上线。先用 curl 模拟几种常见攻击,确认规则确实生效。测试 SQL 注入检测:

curl -v "http://localhost/test.php?id=1' OR '1'='1"

测试 XSS 检测:

curl -v "http://localhost/search?q="

测试路径遍历:

curl -v "http://localhost/download?file=../../../etc/passwd"

正常的阻断响应应该是 403 Forbidden,同时在审计日志中能看到详细的匹配记录。查看审计日志确认规则触发情况:

sudo tail -f /var/log/modsecurity/audit.log | grep -A 10 "id \"942"

如果请求没有被阻断,检查 ModSecurity 的调试日志,把 SecDebugLogLevel 临时调到 3,可以看到规则处理的完整流程。注意调试完成后一定要调回 0,否则日志会迅速撑满磁盘。

日常维护和规则更新

OWASP CRS 项目更新频繁,平均每个月都有新版本发布,修复误报和增加新规则。更新规则集用 git pull 即可:

cd /etc/modsecurity/crs
sudo git pull

更新后务必对比新旧 crs-setup.conf 的差异,因为新版本可能会引入新的配置项。用 diff 工具检查:

diff /etc/modsecurity/crs/crs-setup.conf /etc/modsecurity/crs/crs-setup.conf.example

如果有新增的配置项,手动合并到你的配置文件中。更新完成后重启 Apache 让新规则生效:

sudo systemctl reload apache2

还有一个容易被忽视的维护工作是定期分析审计日志。ModSecurity 的审计日志包含了所有触发规则的请求详情,通过分析这些日志可以发现针对你系统的攻击趋势,也能找出需要调优的误报规则。建议写一个简单的脚本,每周统计触发次数最多的规则 ID,针对性地调整阈值或添加排除规则。

性能优化注意事项

ModSecurity 加载完整 CRS 规则集会增加请求处理延迟,通常在 5 到 15 毫秒之间。对于高并发场景,有几个优化方向。第一,关闭响应体检查,除非你需要检测信息泄露。在 modsecurity.conf 中设置 SecResponseBodyAccess Off,可以减少大约 30% 的处理开销。第二,缩小请求体检查范围,对于纯 API 服务,只检查 JSON 和 XML 类型的请求体。第三,使用 ModSecurity 的持久化存储功能,把 IP 黑名单和会话数据存到共享内存中,避免每次请求都重新计算。

如果服务器负载明显升高,先检查是不是某个规则导致了大量回溯匹配。规则 942370 和 942380 这类包含复杂正则的规则对 CPU 消耗较大,如果确认误报率低且攻击场景不相关,可以考虑关闭。但要注意,每关闭一条规则就少一层防护,权衡取舍要基于实际的日志数据,不要凭感觉操作。