很多 Web 中间件可以通过ACL来对 HTTP 路径或资源进行安全管控,比如我们想要配置 Nginx 使其禁止访问/admin路径,可以这样配置:
当请求经过 Nginx 处理,被其放行后,才会到达后端服务。试想一下,如果一个请求在 Nginx 看来并不是访问/admin路径,从而放行请求,而在后端服务处理时又把它路由到/admin上去,岂不是一次绕过 ACL 的越权访问
而无论是 Nginx 等中间件还是后端的 Web 服务,在处理请求路径时,通常都会对路径进行规范化处理,清除路径中的特殊字符、空白字符等,如果前后处理存在差异,就可能导致安全问题(本质上和HTTP request smuggling很相似)
那么从最常用的trim/strip函数入手,不同语言的实现存在一些区别。比如 python 的 strip()
会清除\x85
,而 JavaScript 的 trim()
不会;Nginx 使用的 C 语言会清除\x09 \xa0 \x0c
等字符,JavaScript 也不会。这种实现上的差异会导致HTTP Desync漏洞
如图所示,由于 Nginx 不会清除路径中的特殊字符,会将请求放行;而后端的 NodeJS 清除了特殊字符后会将请求路由到/admin页面,导致越权访问
针对 NodeJS 实现的后端服务,可以参照以下表格绕过 Nginx ACL
Nginx Version | Node.js Bypass Characters |
---|---|
1.22.0 | \xA0 |
1.21.6 | \xA0 |
1.20.2 | \xA0, \x09, \x0C |
1.18.0 | \xA0, \x09, \x0C |
1.16.1 | \xA0, \x09, \x0C |
针对 Flask 实现的后端服务(或者其他 python 实现应该也适用?)
Nginx Version | Flask Bypass Characters |
---|---|
1.22.0 | \x85, \xA0 |
1.21.6 | \x85, \xA0 |
1.20.2 | \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B |
1.18.0 | \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B |
1.16.1 | \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B |
针对 SpringBoot
Nginx Version | Spring Boot Bypass Characters |
---|---|
1.22.0 | ; |
1.21.6 | ; |
1.20.2 | \x09, ; |
1.18.0 | \x09, ; |
1.16.1 | \x09, ; |