CORS安全漏洞解析:跨域资源共享的风险与防护

本文深入剖析CORS(跨域资源共享)机制中的安全风险,重点讲解Access-Control-Allow-Origin和Access-Control-Allow-Credentials头部的错误配置如何导致严重安全漏洞,并通过可视化图表展示不同配置场景下的安全影响。

CORS Lite

跨域资源共享(CORS)机制非常复杂,这种复杂性导致了许多可能隐藏安全漏洞的地方。本文将为您提供CORS的"精简版"概述,重点关注我们在测试中最常见的安全漏洞。本文并非完整的CORS入门指南——如果您想深入了解,文末的资源部分会帮助您入门。

CORS基础与安全风险

CORS规范最基本的部分是"Access-Control-Allow-Origin"头部,这是整个机制的基础。该头部告知浏览器允许哪些源访问特定资源。举例来说,如果您的web应用中的JavaScript(从app.example.com加载)向api.example.com发出请求,这个跨域请求默认会被拒绝(即浏览器不会发出请求或会忽略请求结果),除非api.example.com返回"Access-Control-Allow-Origin"头部告诉浏览器这是允许的。

对于API而言,Access-Control-Allow-Origin头部经常被设置为"*",这允许任何域向该API发起跨域请求。这意味着任何地方的任何JavaScript都可以访问您的API。不过幸运的是,即使有Access-Control-Allow-Origin头部,跨域请求也不会传输cookie或其他认证材料,因此这个头部本身实际上是相当安全的。

危险组合:凭证允许头部

真正的风险来自另一个CORS头部:Access-Control-Allow-Credentials。当返回这个头部时,跨域请求可以包含cookie和其他认证材料。这才是问题真正开始的地方。如果用户访问example.com,并且example.com在其浏览器中设置了cookie(比如登录后),Access-Control-Allow-Credentials头部将允许该cookie被来自其他域的请求发送。这意味着这些域可以使用example.com设置的cookie来在example.com上执行操作,无论谁控制着这些域上运行的JavaScript!

如果对example.com的请求返回Access-Control-Allow-Origin: foo.bar头部和Access-Control-Allow-Credentials: true头部,那么foo.bar上的任何脚本都将拥有与example.com原生脚本相同的权限。这意味着foo.bar上的XSS漏洞等同于example.com上的XSS漏洞!如果您是example.com的所有者,这是对另一个站点所有者的极大信任,在这样做之前应该非常谨慎地考虑。

安全防护机制与绕过风险

由于Access-Control-Allow-Credentials头部非常危险,有一些保护措施可以防止意外使用它。首先,它不能与Access-Control-Allow-Origin: *组合使用。有些站点通过简单地将请求中的Origin头部反射回响应中的Access-Control-Allow-Origin头部来绕过这个限制。如果您考虑这样做,请务必仔细考虑您承担的风险。

另一个对Access-Control-Allow-Credentials头部的限制是在客户端——XMLHttpRequest必须特意设置"withCredentials"标志才能请求发送凭证,以确保您确实希望浏览器随跨域请求发送cookie和其他敏感材料。

关键安全结论

最重要的结论是:如果您将Origin头部反射到Access-Control-Allow-Origin头部中,并同时设置Access-Control-Allow-Credentials: true,那么任何能够在用户浏览器中执行恶意JavaScript的攻击者(无论该JavaScript位于何处)都可以劫持该用户在您应用中设置的cookie,并以该用户的身份进行操作。

有些应用尝试折中方案,手动验证origin头部而不是简单地反射它——例如,任何匹配"*.example.com"的来源都被认为是"安全的",并会返回到Access-Control-Allow-Origin头部中。但这里存在问题:攻击者可以诱使用户访问"example.com.malicious.com"(可能通过钓鱼),因为该站点匹配模式,就可以发起与之前相同的攻击!

其他资源

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计