访问漏洞
2017年,访问漏洞一位安全研究员在酒店房间里盯着终端屏幕,访问漏洞手指停在回车键上方。访问漏洞他刚刚向目标服务器发送了一个请求,访问漏洞URL里多了一个点——https://example.com./admin。访问漏洞浏览器正常打开是访问漏洞404,但这个带点的访问漏洞版本返回了200。后台管理页面完整地呈现在他眼前,访问漏洞不需要密码,访问漏洞不需要token,访问漏洞什么都没有。访问漏洞
这就是访问漏洞访问漏洞。听起来像天方夜谭,访问漏洞但它真实存在,访问漏洞而且至今仍在各种系统里反复出现。访问漏洞
问题的根源往往藏在反向代理和源站之间的信任关系里。Nginx、HAProxy这类代理服务器收到请求后,会先做一轮路由判断——哪些路径放行,哪些拦截。判断完了,它把请求转发给后端的应用服务器。关键在于:代理判断用的URL,和应用最终解析的URL,可能不是同一个东西。
举个例子。代理规则写着“/admin路径禁止外部访问”。攻击者发来/admin/..%2fpublic,代理看一眼,觉得路径里没有敏感的admin段,放行。请求到了后端,后端把%2f解码成/,再处理..做路径归一化,最终实际访问的是/public——等等,这个例子还不够狠。换成/public/..%2fadmin,代理看到的是public开头,放行;后端解码归一化之后,实际请求的是/admin。防线就这么被绕过去了。
我见过一个更离谱的案例。某云服务商的API网关用正则匹配来拦截未授权路径,规则写的是^/api/v1/internal/。攻击者用/api/v1/internal%2f..%2f..%2fpublic/secret,正则匹配失败因为字符串里没有连续的/internal/,网关放行。后端框架解码后得到/api/v1/public/secret,但中间件已经根据原始路径做了权限判定——判定结果是“非internal路径,无需鉴权”。双重解码加上判定与执行用的路径不一致,漏洞就出来了。
这类问题很难被自动化扫描器发现。扫描器通常只测单一编码、单一变换,不会去穷举代理层和应用层之间的解析差异组合。人工测试反而更容易命中,因为你可以观察到一个反常现象:同一个资源,换个写法就进去了。
防御思路其实不复杂,但执行起来需要耐心。代理层和应用层必须用同一套标准化逻辑来处理路径。最稳妥的做法是在代理层就把路径归一化、解码、再归一化,然后把处理后的结果传给后端,而不是传原始URL。后端拿到之后不要再做二次解码。两边对“这个请求到底访问哪个资源”的判断必须完全一致。
另一个细节:不要依赖字符串匹配来做安全决策。strstr、正则、前缀判断,在面对编码变换时全都可能失效。路径安全判断应该基于归一化之后的规范化路径,而不是原始输入。
回到开头那个案例。研究员后来在报告里写了一句让我印象深刻的话:“我不是绕过了防火墙,我是让防火墙和后面的服务器吵了一架,然后趁它们吵架的时候走了进去。”访问漏洞的本质就是这样——不是攻破某一道防线,而是利用两道防线之间的认知差异。只要系统里还有多个组件各自解析同一个URL,这种漏洞就不会消失。









