在Ubuntu服务器上直接裸奔Web应用,等于把房子建在闹市却不装门锁。ModSecurity作为一款开源的Web应用防火墙,能实时监控和拦截SQL注入、跨站脚本、文件包含等攻击。但光装上引擎没用,你得给它配上好规则。OWASP ModSecurity核心规则集(CRS)是目前全球公认的、维护最活跃的恶意流量识别标准,把这两者结合,就能用最低成本构建起一套强悍的防护体系。下面直接进入实操,从零开始在Ubuntu系统上完成部署和调优。
环境准备与依赖安装本文以Ubuntu 22.04 LTS和Apache 2.4为例,Nginx的流程会单独说明。先更新系统包列表并安装必要工具,这一步不能跳过,因为不少安全漏洞都源于过期组件。
sudo apt update && sudo apt upgrade -y sudo apt install apache2 apache2-utils libapache2-mod-security2 -y
安装完成后,ModSecurity模块默认会被启用。执行以下命令确认模块已加载:
sudo apachectl -M | grep security
如果看到“security2_module”字样,说明模块已就绪。此时ModSecurity自带一个默认配置文件,但规则集是空的,基本等于摆设。我们需要用OWASP CRS来替换它。
获取并部署OWASP核心规则集OWASP CRS的官方仓库在GitHub上维护,版本迭代很快。推荐使用Git克隆的方式获取,方便后续一键更新。先安装Git:
sudo apt install git -y
然后进入ModSecurity目录,把原有的默认规则集备份一下,再克隆最新版CRS:
cd /etc/modsecurity/ sudo mv modsecurity.conf-recommended modsecurity.conf sudo git clone https://github.com/coreruleset/coreruleset.git /etc/modsecurity/crs
克隆完成后,crs目录下会有一个“rules”文件夹,里面包含了几十个按攻击类型分类的规则文件。但直接使用这些文件会导致ModSecurity加载失败,因为缺少核心配置。我们需要复制一份CRS自带的设置模板:
sudo cp /etc/modsecurity/crs/crs-setup.conf.example /etc/modsecurity/crs/crs-setup.conf
这个crs-setup.conf文件是整套规则的总控开关,控制着防护等级、阈值、白名单等关键参数,后面会详细讲解如何调优。
配置ModSecurity加载OWASP规则现在要让ModSecurity知道去哪里找规则。编辑Apache中ModSecurity的主配置文件:
sudo nano /etc/apache2/mods-enabled/security2.conf
在文件中找到Include相关的行,修改为以下内容,确保同时包含CRS配置文件和各条具体规则:
<IfModule security2_module>
SecDataDir /var/cache/modsecurity
Include /etc/modsecurity/modsecurity.conf
Include /etc/modsecurity/crs/crs-setup.conf
Include /etc/modsecurity/crs/rules/*.conf
</IfModule>
注意SecDataDir这个路径,ModSecurity运行时需要在此目录存放持久化数据,比如IP黑名单。手动创建并设置权限:
sudo mkdir -p /var/cache/modsecurity sudo chown www-data:www-data /var/cache/modsecurity
接下来修改ModSecurity的主运行参数。打开modsecurity.conf文件:
sudo nano /etc/modsecurity/modsecurity.conf
找到SecRuleEngine这一行,把默认的“DetectionOnly”改成“On”。这是最关键的一步,否则ModSecurity只会记录攻击而不拦截,等于监控摄像头只录像不报警。
SecRuleEngine On
同时建议把SecResponseBodyAccess也设为On,这样能检查响应体中的敏感信息泄露,比如服务器版本号或错误堆栈。完成后保存退出,重启Apache让配置生效:
sudo systemctl restart apache2
如果重启失败,多半是规则语法错误或路径不对,用以下命令检查错误日志:
sudo tail -f /var/log/apache2/error.log理解OWASP CRS的防护等级与异常评分
OWASP CRS不像商业WAF那样开箱即用,它用一套“异常评分”机制来决定是否拦截请求。每个请求进来,规则会逐条匹配,命中一条就累加分数。当总分超过阈值,ModSecurity就阻断该请求。这套机制的核心参数在crs-setup.conf里,需要你根据业务场景调整。
打开crs-setup.conf,找到tx.paranoia_level这个参数:
SecAction \ "id:900000,\ phase:1,\ nolog,\ pass,\ t:none,\ setvar:tx.paranoia_level=1"
偏执等级从1到4,数字越大规则越严格,误报率也越高。等级1是推荐起点,适合大多数生产环境;等级2会启用更多正则表达式检查,适合对安全要求较高的站点;等级3和4会触发大量额外规则,误报极高,通常只用于安全审计或临时应急。新手建议从1开始,跑一周日志后再逐步提升。
另一个关键参数是tx.inbound_anomaly_score_threshold和tx.outbound_anomaly_score_threshold,分别控制入站和出站流量的拦截阈值。默认值是5和4,意味着入站请求累计5分就阻断。这个值可以适当调高,比如设为10,减少误杀。
处理常见误报与白名单配置部署完CRS后,你几乎必然会遇到误报。比如WordPress后台的某些复杂编辑器操作、文件上传功能、或者URL中包含特殊字符的正常业务请求,都可能被误判为攻击。直接关掉整条规则是最粗暴的做法,正确的方式是编写白名单规则,精确排除特定URL或参数。
在crs-setup.conf同目录下,创建一个专门放白名单的文件,比如REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf,并确保它在所有CRS规则之前加载。编辑security2.conf,在Include CRS规则之前加入这一行:
Include /etc/modsecurity/crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
白名单规则的编写需要遵循ModSecurity语法。举个例子,如果你的应用有一个回调URL /api/webhook,经常被规则920420(检查Content-Type)误拦,可以这样排除:
SecRule REQUEST_URI "@beginsWith /api/webhook" \ "id:1000,\ phase:1,\ pass,\ nolog,\ ctl:ruleRemoveById=920420"
更推荐的做法是使用CRS内置的排除规则模板。CRS从3.2版本开始提供了更细粒度的排除机制,可以在crs-setup.conf中找到“Exclusion Rules”相关注释,按模板启用即可。每次添加白名单后,务必用以下命令测试配置语法:
sudo apachectl configtestNginx环境下的部署差异
如果你用的是Nginx,ModSecurity需要以动态模块方式编译进去,或者使用独立的ModSecurity-nginx连接器。Ubuntu官方源里的libnginx-mod-security包可以直接安装:
sudo apt install libnginx-mod-security -y
安装后,在nginx.conf的http块中加载模块并指定规则文件:
load_module modules/ngx_http_modsecurity_module.so; modsecurity on; modsecurity_rules_file /etc/modsecurity/modsecurity.conf;
其他CRS的配置和Apache完全一致,规则文件路径相同。注意Nginx下ModSecurity的SecRuleEngine同样要设为On,且每次修改规则后需重载Nginx:
sudo nginx -t && sudo systemctl reload nginx日志监控与持续优化
部署完成不代表结束,持续监控日志才是WAF发挥价值的关键。ModSecurity的审计日志默认写入/var/log/modsec_audit.log,格式分多个部分:A部分为审计日志头,B部分为请求头,C部分为请求体,H部分为匹配的规则详情。重点看H部分,它会告诉你哪条规则命中、得分多少、具体匹配了什么内容。
为了方便分析,可以把ModSecurity日志接入集中式日志平台。如果只是单机排查,用grep和cut就能快速统计高频误报规则:
sudo grep "H:" /var/log/modsec_audit.log | cut -d' ' -f4 | sort | uniq -c | sort -rn | head -20
这条命令会列出触发次数最多的20条规则ID。拿着这些ID去CRS官方文档查含义,判断是真实攻击还是业务误报,再决定是加白名单还是调低偏执等级。
另外,建议把SecDebugLogLevel设为1或2,不要设太高,否则日志会爆炸式增长。生产环境用等级1记录基本错误即可,调试阶段可以临时开到3。
规则集自动更新策略OWASP CRS每隔几个月就会发布新版本,修复误报、增加新规则或提升性能。用Git部署的好处是可以一键更新。进入CRS目录,拉取最新代码,然后检查crs-setup.conf是否有新增配置项需要合并:
cd /etc/modsecurity/crs sudo git pull sudo diff crs-setup.conf crs-setup.conf.example
diff命令会对比你的当前配置和最新模板,手工把新增的必要参数合并进去。更新规则后务必重载Apache或Nginx,并在测试环境先验证,避免新规则直接上生产引发大面积误拦。
如果担心自动更新带来的风险,可以固定使用某个Release版本。GitHub上每个Release都有对应的压缩包,下载后解压到crs目录即可,这样版本更可控。
性能影响与硬件资源评估开启ModSecurity并加载全套CRS规则,会消耗额外的CPU和内存。每条请求都要经过几百条正则表达式的匹配,尤其在偏执等级较高时,延迟增加可能达到几十毫秒。对于日均请求量在百万级别以下的站点,现代CPU完全能扛住;但如果你的业务是API网关或高并发场景,需要做性能评估。
优化方向有几个:一是把静态文件(图片、CSS、JS)从WAF检查中排除,在Apache或Nginx层面直接返回,不让请求到达ModSecurity;二是调整CRS规则加载数量,在crs-setup.conf中按需禁用整个规则组,比如没有用到REST API就可以禁用REQUEST-913-*系列规则;三是使用ModSecurity的缓存机制,SecCollectionTimeout参数可以设置IP黑名单等集合的缓存时间,减少重复查询。
整套流程走下来,你的Ubuntu服务器就拥有了一款企业级WAF。它不能替代代码层面的安全审计,但能作为最后一道防线,在漏洞被利用之前把攻击挡在门外。关键在于持续关注日志、迭代白名单、跟上规则更新,这三件事做扎实了,OWASP CRS的防护效果会远超很多商业产品的基础版本。
