secruleengine on 且规则正确配置才能有效防御——需确认模块加载、路径准确、secdatadir 可写,先用 detectiononly 模式调试,禁用响应体检查减负载,注意变量、phase、action 误用,并用最小可行规则验证 sqli/xss 防御。

直接启用 SecRuleEngine On 并写几条 SecRule 不等于防御有效——规则位置错、phase 选错、变量名拼错、没关 SecResponseBodyAccess,都会导致日志满屏却拦不住真实攻击。
确认 mod_security2 模块已加载且配置路径正确
Apache 启动后必须看到 security2_module 被加载,否则所有规则都不生效:
- 运行
a2enmod security2(Ubuntu/Debian)或检查httpd.conf中是否含LoadModule security2_module modules/mod_security2.so -
Include规则文件的路径必须与实际存放位置一致;常见错误是把/etc/modsecurity/*.conf写成/etc/modsecurity/conf.d/*.conf却没建对应目录 - 验证是否加载成功:
apache2ctl -M | grep security输出应为security2_module (shared) - 若用宝塔或自编译 Apache,
SecDataDir必须指向可写路径,比如/var/cache/modsecurity或/www/server/apache/cache/modsecurity,否则规则初始化失败静默退出
写第一条拦截规则前先设对 SecRuleEngine 和日志模式
刚配好就开 SecRuleEngine On 容易误杀业务,应分两步走:
PHP中文网提供Apache 2.4.62 官方 tar.gz 源码包下载,通过源码编译安装,开发者能够灵活定制模块、优化性能并精准控制安装路径,满足多样化的业务需求。
- 先设为
SecRuleEngine DetectionOnly,配合SecAuditEngine RelevantOnly和SecAuditLog /var/log/apache2/modsec_audit.log,只记录不拦截,观察真实流量匹配情况 - 禁用响应体检查:
SecResponseBodyAccess Off(除非你真要防数据泄露),否则每个响应都缓存+解析,CPU 和磁盘 I/O 明显升高 - 限制请求体大小:
SecRequestBodyLimit 13107200(12.5MB),避免大文件上传触发 OOM;同时设SecRequestBodyNoFilesLimit 131072(128KB)控制非文件参数内存占用 - 修改完必须
systemctl reload apache2(不是 restart),否则新规则不加载
SecRule 变量、phase、action 的典型误用点
规则写出来但不触发?八成卡在以下三个地方:
-
ARGS只覆盖 URL 查询参数和 POST 表单键值,不包含 JSON body —— 要匹配 JSON 需用REQUEST_BODY+SecRequestBodyAccess On,且需确保前端发的是Content-Type: application/x-www-form-urlencoded或显式开启 JSON 解析(v3 才原生支持) -
phase:2是最常用阶段,但登录接口常需在phase:1拦异常 User-Agent 或空 Referer,而防信息泄露规则(如匹配phpinfo())必须放phase:4扫响应体 -
deny会直接返回 403,但有些场景要用block(配合SecResponseBodyAccess On返回自定义页面)或redirect;漏写id会导致规则无法被 CRS 引用或禁用 - 正则操作符写成
@rx而非@rx(注意空格),或用@streq匹配大小写敏感字符串时没加t:lowercase变换,都让规则形同虚设
防御 SQLi/XSS 的最小可行规则示例
别一上来就抄 CRS 全集,先跑通一条能拦住真实攻击的规则:
SecRule ARGS "@rx (?i)(union\s+select|select\s+.*\s+from|insert\s+into|drop\s+table)" \
"id:1001,phase:2,deny,status:403,msg:'SQLi keyword detected',logdata:%{MATCHED_VAR_NAME}=%{MATCHED_VAR}"
再加一条防基础 XSS:
SecRule ARGS|REQUEST_HEADERS:User-Agent "@rx (?i)<script attempt detected> <ul> <li>两个规则都加了 <code>(?i) 实现忽略大小写匹配 <li><code>logdata 记录具体哪个变量、哪个值触发,排查误报时比翻完整 audit log 快得多 <li>别用 <code>@detectSQLi 这类 CRS 封装操作符——它依赖 <code>crs-setup.conf 初始化,单独用会报错 <code>Unknown operator <li>上线前用 <code>curl -v "http://yoursite/?q=1%20union%20select" 测试,看是否返回 403 且日志里出现 <code>id "1001" <p>真正难的不是写规则,而是判断哪条规则该放 phase:1 还是 phase:2,以及怎么让 <code>REQUEST_BODY 在 multipart/form-data 场景下也能被解析——这需要额外启用 <code>SecRule REQUEST_HEADERS:Content-Type "multipart/form-data" "id:9001,phase:1,t:none,pass,nolog,ctl:requestBodyProcessor=URLENCODED",否则文件上传参数永远进不了 <code>ARGS。 </script>










