2017年,漏洞某电商平台的漏洞一次常规安全扫描中,工程师发现一个诡异现象:用户修改收货地址的漏洞请求,在未登录状态下居然返回了200状态码。漏洞进一步测试后确认,漏洞只要把请求中的漏洞用户ID从自己的改成别人的,就能任意查看、漏洞修改他人的漏洞订单信息。问题出在一个不起眼的漏洞HTTP参数上——系统信任了客户端传来的身份标识,却没有在服务端做二次校验。漏洞这就是漏洞典型的HTTP漏洞,一个比SQL注入更隐蔽、漏洞比XSS更直接的漏洞攻击面。
HTTP协议本身是漏洞无状态的,每次请求独立,漏洞服务器不记得你是谁。为了维持会话,开发者发明了Cookie、Session、Token。问题恰恰出在这里——当身份凭证通过HTTP头、URL参数或Cookie传递时,任何环节的疏忽都可能让攻击者绕过认证。上面那个案例中,后端代码大概写了类似if (request.getParameter("user_id") != null) { queryOrder(user_id); }的逻辑,完全没检查当前会话的用户是否匹配这个ID。攻击者不需要高深技术,改个数字就行。
更常见的是HTTP响应头配置不当。比如缺失HttpOnly标志的Cookie,JavaScript能直接读取,XSS攻击一旦得手,会话令牌立刻泄露。再比如X-Frame-Options没设,页面被嵌入iframe,点击劫持就来了。还有Content-Security-Policy缺位,浏览器对脚本来源毫无限制。这些都不是理论风险。某银行网站曾因未设置Strict-Transport-Security,用户在公共WiFi下访问时被中间人降级到HTTP,登录凭证明文传输。
请求方法滥用也值得说。很多API只检查URL和参数,不校验HTTP方法。一个只该接受POST的删除接口,用GET请求也能触发。攻击者构造一个<img src="https://api.example.com/delete?id=123">,用户浏览页面时浏览器自动发GET,数据就没了。更隐蔽的是HEAD或OPTIONS方法泄露内部信息,比如Allow头直接告诉攻击者支持哪些方法。
参数污染是另一个坑。HTTP允许同名参数重复出现,?id=1&id=2,不同服务器解析方式不同。有的取第一个,有的取最后一个,有的拼成数组。攻击者利用这个差异绕过WAF规则或业务逻辑校验。某次渗透测试中,安全人员发现目标系统用id=1校验权限,但后端取的是最后一个值,改成id=1&id=999就直接越权了。
防御层面,核心原则就一条:永远不要信任客户端传来的任何东西。身份标识必须从服务端会话中取,不能从请求参数里读。Cookie加HttpOnly、Secure、SameSite三个属性,成本极低,效果立竿见影。响应头该设的都设上,X-Content-Type-Options: nosniff能防MIME混淆攻击。方法校验别偷懒,该拒绝的请求直接返回405。
工具层面,Burp Suite的Repeater和Intruder模块是手工测试HTTP漏洞的标配。自动化扫描器能覆盖一部分,但逻辑漏洞它看不出来。上面那个越权案例,扫描器跑了三遍都没报警,因为返回的是200和正常数据,没有报错、没有异常状态码。只有人去看请求和响应的对应关系,才能发现不对劲。
HTTP漏洞的可怕之处在于它太基础了。开发者觉得“不就是个请求吗”,安全人员觉得“这玩意儿有啥好讲的”。但正是这种轻视,让越权、会话固定、CSRF、点击劫持反复出现在OWASP Top 10里。每次出事儿,回头看代码,往往就是少了一行if (session.getUserId() != request.getUserId()) return 403;。一行代码的事,但没写,就是洞。