本文目录导读:

这是一个非常专业且切中要害的问题,很多安全团队(特别是甲方)在配置WAF时,容易陷入“规则越多越安全”或“直接开拦截模式”的误区,导致误报率飙升或绕过漏洞频出。
要写出有效的WAF规则,核心方法论是:基于攻击原理做“语义分析”,而不是基于特征做“关键词匹配”。
以下是编写有效WAF规则的五个核心原则和具体实践指南:
有效规则的核心原则
- 精准打击,拒绝误报:规则应命中攻击语法,而非普通业务参数,拦截
union select不如拦截union select [SQL语句](带空格、注释符或闭合符)。 - 分层防御:不要在入口层试图解决所有问题,规则应分三层:
- 黑名单(已知攻击):拦截已知的Payload特征。
- 白名单(业务例外):允许业务正常输入(如富文本、数学公式)。
- 异常检测(未知攻击):基于语法、长度、熵值(信息熵)检测异常。
- 上下文感知:必须知道“参数”是干什么的。
?id=1只期待整数,出现字母应该直接拦截。?name=张三期待中文,出现<script>应该拦截。
- 性能优先:复杂的正则表达式会导致WAF CPU飙升,拖垮源站。
- 使用正则引擎优化(避免回溯爆炸)。
- 尽量使用状态机或树形匹配(如AC自动机)。
- 避免“万能规则”:不要写
.*select.*或.*drop.*这种规则,这会拦截掉所有包含“select”的正常业务(如“请选择城市”)。
针对Top攻击类型的规则写法(实战示例)
SQL注入(最核心,也最常写错)
- 错误写法:
if (payload contains "select") { block },攻击者用SeLeCt、sel/**/ect、SELECT均可绕过。 - 有效写法(基于词法和闭合):
- 检测恒等式:
/\d+\s+(union|and|or)\s+\d+\s*[=<>]/i(拦截1 and 1=1,但不拦截1 and the year is 2023)。 - 检测注释符: (拦截SQL注释,但不拦截正常代码中的“/*
- 检测闭合括号:对于)或的异常出现次数,传入的参数中单引号数量为奇数且无业务必要,应告警。
- 最佳实践:WAF规则应该关注“SQL语法结构”的插入,而不是“关键词”。 优先使用WAF的SQL语义分析引擎(如果支持),而不是写正则。
- 检测恒等式:
XSS(跨站脚本攻击)- 防绕过难度高
- 错误写法:
if (payload contains "<script>") { block }。<img src=x onerror=alert(1)>直接绕过。 - 有效写法(检测事件和协议):
- 检测事件处理:
/\s(on\w+)\s*=/i(拦截onerror=、onload=、onfocus=等)。这是XSS规则里最核心的一条。 - 检测危险协议:
/javascript\s*:/i、/data\s*:/i。 - 检测SVG/HTML标签嵌套:
/<\w+\s+[^>]*?\/?\s*>.*?<\/\w+>/i(针对富文本场景,需与白名单配合)。 - CSS注入:
/expression\s*\(|behavio?r\s*:/i。
- 检测事件处理:
- 关键点:XSS规则一定要关注标签的闭合和事件属性的冒号。
命令注入
- 有效写法:
- 检测管道符与系统命令组合:
/[|;&$\n]+\s*(cmd|powershell|bash|sh|python|perl)/i`(注意,只匹配命令前缀而不是整个路径)。 - 检测反引号: (反引号在Shell中是执行子命令,直接拦截)。
- 检测写入操作:
/>(>)?|echo.*\|.*tee|wget.*-O/i(拦截写入文件的行为)。
- 检测管道符与系统命令组合:
文件包含/路径穿越
- 有效写法:
- 检测目录回溯: (必须是连续的两个点加斜杠)
- 检测绝对路径:
/(?:^|\?|&)\w*=\/etc\//i(针对类似?file=/etc/passwd)。 - 检测协议包含:
/(php|file|http|https|ftp):\/\//i(针对include('http://evil.com/shell.txt'))。
高级优化:减少误报与性能开销
-
参数类型的精准分类:
- 数字型参数:
/^\d+$/(匹配通过,否则拦截)。 - URL参数:
/^https?:\/\/[^\s<>]+$/i。 - 文本参数:去HTML化后再检测XSS规则。
- 数字型参数:
-
白名单优先(非常重要):
- 对于编辑器(TinyMCE, CKEditor)、接口文档(Swagger)、语言包等固定格式的请求,直接放行或只做格式校验,不做深度检测。
-
响应检测(RCE & 数据泄露):
- 有效规则:检查HTTP响应Body中是否包含
id=、uid=以及大段的<?php或SELECT...FROM。 - 应用场景:用于检测RCE的反弹结果或SQL注入的盲注成功(当响应中的数据库信息出现时告警)。
- 有效规则:检查HTTP响应Body中是否包含
一个“有效规则”的检查清单
写完规则后,请问自己三个问题:
- 【绕过测试】:这条规则能被 、
%0a(换行)、大小写、双写(<scr<script>ipt>)绕过吗? - 【误报测试】:这条规则会拦截“1.5版本”、“旧Select查询”、“
标签”吗? - 【性能测试】:这条正则表达式在10000字长的文本上运行需要多久?(应< 0.1ms)
避坑指南:千万别这样写
- *禁止单条规则包含“.”匹配全量内容*(select|union|exec).*/i`,这会让WAF引擎陷入灾难性回溯,导致服务器CPU满载。
- 不要依赖关键词计数:
count("union") >= 1,攻击者用UNION ALL SELECT或穿袜子。 - 不要忽略协议层工具:WAF规则不要专门为ModSecurity的旧规则库而写,要参考OWASP CRS(核心规则集) 的最新版本(3.x及以上),它已经做了很好的语义化升级。
总结一句:最有效的WAF规则,不是“拦截所有看起来像攻击的字符”,而是“只允许符合业务逻辑的输入通过”。
如果你使用的是商业WAF(如Cloudflare、AWS WAF、阿里云WAF),请优先开启其内置的“托管规则”(Managed Rules),它们由安全团队持续更新,比自己写正则更好用,只针对自己业务的特有漏洞接口(如文件上传、API接口参数格式异常)编写自定义规则。