cors漏洞修复
CORS漏洞修复,漏洞本质上是修复给浏览器这把锁配一把正确的钥匙,而不是漏洞把锁拆了。 前两天看了一个渗透测试报告,修复攻击者用了一个很简单的漏洞Origin头伪造,就从一个子域名的修复JSONP接口里拖走了用户手机号。修复方案写得倒是漏洞干脆——Access-Control-Allow-Origin设成*。这确实修好了CORS报错,修复但等于把整个站点的漏洞数据都挂在了公共广场上,任何恶意站点都能发起跨域读取。修复这不是漏洞修复,是修复裸奔。 CORS的漏洞根子在于,浏览器默认执行同源策略,修复但服务器可以通过响应头显式放行某些跨域请求。漏洞攻击者利用的,恰恰是服务器对Origin校验不严,或者干脆反射任意Origin。你如果只是简单地把Allowed Origin设成*,那等于对所有第三方站点都敞开了大门——只要那个站点愿意发一个带Credentials的请求,用户的Cookie就会跟着过去。 我见过最典型的错误配置长这样: 真正的修复逻辑,应该分三层: 第二层,处理预检请求。非简单请求会先发一个OPTIONS,服务器必须在预检响应里正确返回允许的方法和头字段。很多人只修了实际请求的响应头,忘了预检响应也要带Access-Control-Allow-Headers。结果就是POST请求带了个自定义Header就报错,前端又把withCredentials打开,整个链路就断了。修复时拿curl手动模拟一下OPTIONS,比在浏览器里看报错快得多。 第三层,也是最容易被忽略的——Vary: Origin。如果你根据请求的Origin动态生成Allowed Origin,那么响应必须带`Vary: Origin`,否则CDN或浏览器缓存会把A用户的放行响应缓存下来,给B用户用。B用户如果是一个恶意站点发起的请求,恰好命中缓存,那等于白名单被击穿。这个细节,我在实际代码评审里见过至少五次遗漏。 还有一个更隐蔽的点:有些框架会自动把Origin反射回去,比如Spring的`allowCredentials(true)`配合`allowedOriginPatterns("*")`,它虽然不会回显*,但会把请求的Origin原样返回。这种反射式CORS,只要攻击者把Origin改成受害者的域名,就能直接绕过。所以白名单校验必须在进入业务逻辑之前就完成,而不是等到写响应头的时候才处理。 修CORS漏洞,别急着加响应头。先问自己一个问题:这个接口的数据,如果被一个陌生站点读走,会造成什么损失?如果答案是“会”,那你就老老实实写死域名列表,一个通配符都别用。如果答案是“不会”,那干脆别开CORS,用代理转发或者JSONP都行。 前阵子给一个金融客户做代码审计,他们有个老接口用了`Access-Control-Allow-Origin: https://trusted-partner.com`,看起来没问题。但攻击者发现这个接口支持`Origin: null`——就是那种用iframe的sandbox属性或者data:协议发起的请求,Origin头会变成null字符串。服务器没过滤null,直接把它当合法来源放行了。修复就一行:`if (origin.equals("null")) return;`,但这一行挡住了所有通过沙箱iframe发起的跨域读取。 别信那些“CORS中间件一键修复”的广告。中间件能帮你加响应头,但它不知道你的业务边界在哪里。真正的修复,是把你脑子里的信任模型写进代码里,写明确,写死,写到你半夜被叫起来都能背出来。否则,你只是在给浏览器表演一个“看上去很安全”的假动作。
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
这两行放在一起,就是灾难。因为规范明确说了,Credentials为true时,Allowed Origin不能是*,必须指定具体域名。但很多开发者图省事,直接把*写上去,浏览器会拦截响应,页面报错,然后他们又去网上搜“CORS跨域报错怎么解决”,搜到一篇博客说“把Origin设成*就行”,结果越修越漏。
第一层,明确信任边界。你的接口到底需要给哪些源用?是给自家前端SPA,还是给第三方合作伙伴?把这些域名写死在服务端配置里,用一个白名单做精确匹配。别用正则去模糊匹配,比如你写了个`/^https?:\/\/(.*\.)?example\.com$/`,看着挺严谨,但攻击者注册一个`example.com.evil.com`就能绕过——因为正则里的`.*`是贪婪的,它会把`evil.com`也吞进去。
-
上一篇
-
下一篇
- 最近发表
- 随机阅读
- 搜索
-
- 友情链接
-