Web应用面临的攻击手段里,SQL注入、跨站脚本、路径穿越这类基于HTTP请求的攻击始终占据大头。ModSecurity是Apache下一款成熟的开源Web应用防火墙引擎,而核心规则集CRS(Core Rule Set)则是它官方维护的规则库,两者搭配起来可以覆盖OWASP Top 10中的绝大多数攻击类型。这篇文章围绕ModSecurity的安装、CRS的部署以及常见配置问题,给出一套可以直接照做的操作方案。

一、ModSecurity与CRS各自的角色
先厘清一个容易混淆的概念:ModSecurity本身只是检测引擎,不带规则。它负责拦截HTTP请求和响应,把数据交给规则去判断,如果命中规则再执行相应动作。可以把它理解成一个空壳的防火墙框架,单独安装完之后什么攻击都拦不住。
CRS则是OWASP社区维护的一套通用规则,当前主流版本是CRS 3.x。它通过分析请求头、请求体、URL参数、Cookie等内容,识别可疑特征并给出风险评分(anomaly score)。CRS 3引入了评分模式,单个规则命中不再直接拦截,而是累加分数,达到阈值才中断请求,这种方式大大降低了误报率。
两者的关系类似杀毒软件引擎和病毒库:引擎负责执行,规则库负责识别。所以配置工作其实分两块,一是让ModSecurity在Apache里正常跑起来,二是把CRS正确引入并调整参数。
二、安装ModSecurity并引入CRS
以Debian/Ubuntu为例,安装过程非常简单,直接通过包管理器完成:
apt update apt install libapache2-mod-security2 -y a2enmod security2 systemctl restart apache2
安装完成后,模块自带一份示例配置,复制一份正式启用:
cp /etc/modsecurity/modsecurity.conf-recommended \ /etc/modsecurity/modsecurity.conf
打开复制出来的配置文件,重点关注两个参数。第一个是SecRuleEngine,默认值是DetectionOnly,也就是只记录日志不拦截,建议先用这个模式观察一段时间,确认误报情况后再改为On。第二个是SecRequestBodyAccess,保持On才能检查POST请求体,这是拦截表单注入的关键。
接下来下载CRS。推荐从官方仓库克隆,方便后续跟进版本更新:
cd /etc/modsecurity git clone https://github.com/coreruleset/coreruleset.git crs cp crs/crs-setup.conf.example crs/crs-setup.conf
最后在Apache配置中引入规则。编辑/etc/apache2/mods-enabled/security2.conf,确保包含以下两行:
<IfModule security2_module>
IncludeOptional /etc/modsecurity/*.conf
IncludeOptional /etc/modsecurity/crs/crs-setup.conf
IncludeOptional /etc/modsecurity/crs/rules/*.conf
</IfModule>重启Apache后执行apachectl -M | grep security,看到security2_module说明模块加载成功。此时可以构造一个测试请求验证效果,例如在URL后面拼接?id=1' or '1'='1,如果日志中出现SQL注入相关的命中记录,说明CRS已经生效。
三、关键参数调优与误报处理
CRS默认采用评分模式,阈值在crs-setup.conf中定义。入站请求默认阈值是5分,出站响应默认是4分。每条规则按严重级别计分:严重级别1(critical)记5分,级别2(error)记4分,以此类推。如果你的业务存在大量正常但包含特殊字符的请求,比如富文本编辑器提交的内容,可以适当调高阈值:
SecAction "id:900110,phase:1,pass,nolog,setvar:tx.inbound_anomaly_score_threshold=10" SecAction "id:900111,phase:1,pass,nolog,setvar:tx.outbound_anomaly_score_threshold=6"
遇到具体误报时,直接调阈值是下策,更推荐做规则例外。CRS 3提供了精细的白名单机制,可以通过ctl:ruleRemoveById针对特定URL关闭某条规则,或者用ctl:ruleRemoveTargetById只对某个参数放行:
# 对后台文章编辑接口整体关闭规则942100
SecRule REQUEST_URI "@beginsWith /admin/article/edit" \
"id:1000001,phase:1,pass,nolog,ctl:ruleRemoveById=942100"
# 只对content参数关闭跨站脚本检测
SecRule REQUEST_URI "@beginsWith /admin/article/edit" \
"id:1000002,phase:1,pass,nolog,ctl:ruleRemoveTargetById=941100;ARGS:content"这里要注意自定义规则的id必须避开CRS保留区间,官方建议使用1000000到1999999之间的数字。白名单范围越小越好,整体关闭某条规则可能把风险放大到全站,能针对单一参数处理的就不要针对整个URL处理。
另外别忘了排查阶段善用日志。ModSecurity的审计日志默认写在/var/log/apache2/modsec_audit.log,每条日志会记录完整的请求内容、命中的规则编号以及最终得分。看到误报时,先记下规则ID,再到CRS文档里查这条规则的具体含义,判断是调整规则还是加白名单,不要盲目删规则。
四、上线前的检查清单与常见坑
正式开启拦截前,建议至少在DetectionOnly模式下跑一到两周,统计日志里的高频命中记录,逐条确认是否为误报。上线当天重点检查这几项:SecRequestBodyLimit是否满足业务最大请求体(默认13MB,含文件上传时经常不够);SecResponseBodyAccess是否需要开启(默认Off,检查响应泄露时才打开);后端是否为HTTPS(ModSecurity解析HTTPS变量依赖正确配置)。
常见的坑还有几个。一是CentOS和Ubuntu的默认路径不同,CentOS下模块名是mod_security2,配置目录在/etc/httpd/modsecurity.d,照搬教程命令会报路径错误。二是CRS大版本之间不兼容,从CRS 2升级到CRS 3时旧的自定义规则需要重写,不要直接复用。三是规则文件引入顺序很重要,crs-setup.conf必须在rules/*.conf之前加载,否则变量初始化会失败,Apache启动时可能报语法错误。
整体来说,ModSecurity加CRS的组合学习成本不高,防护效果却相当实在。先跑检测模式、再做规则微调、最后开启拦截,按这个节奏推进,基本能在一台普通配置的服务器上稳定运行,为业务系统挡住绝大多数常见的自动化攻击。
ModSecurity核心规则集CRSApache防火墙配置修改时间:2026-09-04 06:48:35