绕过类漏洞为什么永远修不完
过滤是黑名单思维,绕过是无限集合。修不完不是不够努力,是方向选错了。
过滤和绕过的关系,从来不是「谁的规则更全」。
三个例子,同一个结构
XSS:禁了 <script>,还有 <img onerror>;禁了事件属性,还有 javascript: 伪协议;禁了尖括号,还有 Unicode 编码。
文件上传:禁了 .php,还有 .php5、.phtml;禁了后缀,还有解析漏洞;两样都堵了,还有 filename="shell.jsp;.jpg"——WAF 读到的后缀是 .jpg,Tomcat 读到的是 .jsp。
鉴权:用 endsWith(".js") 放行静态资源,就有人请求 admin/list.do;.js。鉴权代码看到 .js 放行,路由按 ; 之前的部分匹配到后台接口。
三次都是同一件事:过滤规则描述的是「坏东西长什么样」,而攻击者只需要找一个规则没想到的写法。
规则是有限的,写法是无限的。这个不对称,靠加规则解决不了。
真正的修法不是加规则
XSS:输出时按上下文转义,白名单。不是「过滤掉危险字符」,是「只输出允许的内容」。
上传:后缀白名单,且上传目录禁止脚本执行。不是「拦掉危险后缀」,是「只接受这几种」。
鉴权:按资源判断权限。不是「哪些路径不用登录」,是「这个接口需要什么权限」。
共同点很清楚:从「禁止什么」换成「只允许什么」。黑名单要穷举坏的,白名单只需定义好的——后者是有限集合,能被穷举的是它。
那为什么还是修不完
因为白名单要写清楚「允许什么」,这需要理解业务:这个字段到底该接受哪些字符,这个上传到底该收哪些格式。
写黑名单只要列几个关键词,五分钟。赶工期的时候,人一定会选快的那个。
所以绕过类漏洞修不完,不是技术问题,是成本问题。理解这一点,就不会指望「换个更贵的 WAF」能解决。
看到一处黑名单过滤,基本可以预期旁边还有三处。修的时候一起修,不然就是排队等着被同一个思路打穿。
具体手法在 Web 漏洞 那几篇里,这里只讲为什么。