我最近不得不设置Access-Control-Allow-Origin
为*
能够进行跨子域 AJAX 调用。我觉得这可能是一个安全问题。如果我保留该设置,我将面临哪些风险?
6 回答
通过响应Access-Control-Allow-Origin: *
,请求的资源允许与每个来源共享。这基本上意味着任何站点都可以向您的站点发送 XHR 请求并访问服务器的响应,如果您没有实现此 CORS 响应,情况就不会如此。
因此,任何站点都可以代表其访问者向您的站点发出请求并处理其响应。如果您实现了基于浏览器自动提供的某些内容(cookie、基于 cookie 的会话等)的身份验证或授权方案之类的实现,则第三方站点触发的请求也将使用它们。
这确实会带来安全风险,特别是如果您不仅允许选定资源共享资源,而且允许每个资源共享资源时。在这种情况下,您应该看看何时启用 CORS 是安全的?.
更新 (2020-10-07)
Current Fetch Standard在凭据模式设置为 时忽略凭据include
,如果Access-Control-Allow-Origin
设置为*
。
因此,如果您使用基于 cookie 的身份验证,则不会在请求中发送您的凭据。
Access-Control-Allow-Origin: *
添加到任何资源是完全安全的,除非该资源包含受标准凭据以外的东西保护的私有数据。标准凭据是 cookie、HTTP 基本身份验证和 TLS 客户端证书。
例如:受 cookie 保护的数据是安全的
想象一下https://example.com/users-private-data
,这可能会根据用户的登录状态暴露私人数据。此状态使用会话 cookie。添加到此资源是安全Access-Control-Allow-Origin: *
的,因为此标头仅在没有 cookie 的情况下允许访问响应,并且需要 cookie 才能获取私有数据。结果,没有私人数据被泄露。
例如:受位置 / ip / 内部网络保护的数据不安全(不幸的是,在 Intranet 和家用电器中很常见):
想象一下https://intranet.example.com/company-private-data
,它会暴露公司的私人数据,但只有在公司的 wifi 网络上才能访问。添加到此资源是不安全的,因为它使用标准凭据以外的其他东西进行保护。Access-Control-Allow-Origin: *
否则,错误的脚本可能会将您用作通往 Intranet 的隧道。
经验法则
想象一下,如果用户在隐身窗口中访问资源,他们会看到什么。如果您对每个人都看到此内容(包括浏览器收到的源代码)感到满意,则可以安全地添加Access-Control-Allow-Origin: *
.
AFAIK,Access-Control-Allow-Origin 只是从服务器发送到浏览器的 http 标头。将其限制在特定地址(或禁用它)不会使您的网站更安全,例如机器人。如果机器人愿意,他们可以忽略标题。默认情况下,常规浏览器(Explorer、Chrome 等)支持标题。但是像Postman这样的应用程序只是忽略了它。
服务器端在返回响应时实际上并没有检查请求的“来源”是什么。它只是添加了 http 标头。发送请求的浏览器(客户端)决定读取访问控制标头并对其采取行动。请注意,在 XHR 的情况下,它可能会使用特殊的 'OPTIONS' 请求来首先请求标头。
因此,任何具有创造性脚本能力的人都可以轻松忽略整个标题,无论其中设置了什么。
另请参阅设置 Access-Control-Allow-Origin 的可能安全问题。
现在来实际回答这个问题
我不禁觉得我将我的环境置于安全风险之中。
如果有人想攻击你,他们可以轻松绕过 Access-Control-Allow-Origin。但是通过启用“*”,您确实可以为攻击者提供更多“攻击向量”,例如使用支持该 HTTP 标头的常规网络浏览器。
以下是作为评论发布的 2 个示例,当通配符确实有问题时:
假设我登录银行的网站。如果我转到另一个页面然后返回我的银行,由于 cookie,我仍然在登录。互联网上的其他用户可以像我一样在我的银行访问相同的 URL,但是如果没有 cookie,他们将无法访问我的帐户。如果允许跨域请求,恶意网站可以有效地冒充用户。
–布拉德
假设你有一个普通的家用路由器,比如 Linksys WRT54g 什么的。假设路由器允许跨域请求。我网页上的脚本可以向常见的路由器 IP 地址(如 192.168.1.1)发出 HTTP 请求,并重新配置您的路由器以允许攻击。它甚至可以将您的路由器直接用作 DDoS 节点。(大多数路由器都有测试页面,允许 ping 或简单的 HTTP 服务器检查。这些可以被大量滥用。)
–布拉德
我觉得这些评论应该是答案,因为它们用现实生活中的例子解释了问题。
这个答案最初是作为对这个问题的回复而写的,What are the security implications of setting Access-Control-Allow-Headers: *, if any?
尽管与这个问题无关,但还是被合并了。
将其设置为通配符*
,意味着允许除安全列表之外的所有标头,并删除确保它们安全的限制。
这些是被认为是安全的 4 个安全列表标头的限制:
- 对于 Accept-Language 和 Content-Language:只能具有由
0-9
、A-Z
、a-z
、 空格或组成的值*,-.;=
。- 对于 Accept 和 Content-Type: 不能包含 CORS 不安全的请求标头字节:(
0x00-0x1F
除了0x09
(HT),这是允许的)"():<>?@[\]{}
、 和0x7F
(DEL)。- 对于 Content-Type:需要具有其解析值(忽略参数)的 MIME 类型,即
application/x-www-form-urlencoded
、multipart/form-data
或text/plain
。- 对于任何标头:值的长度不能大于 128。
为简单起见,我将根据这些标题来回答。
根据服务器实现,简单地删除这些限制可能非常危险(对用户而言)。
例如,这个过时的 wordpress 插件有一个反射型 XSS 漏洞,其中的值Accept-Language
被解析并按原样呈现在页面上,如果值中包含恶意负载,则会导致用户浏览器上的脚本执行。
使用通配符 header Access-Control-Allow-Headers: *
,重定向到您网站的第三方站点可以将 header 的值设置为Accept Language: <script src="https://example.com/malicious-script.js"></script>
,因为通配符删除了上面第 1 点中的限制。
然后,预检响应会对此请求开绿灯,并且用户将被重定向到您的站点,从而在他们的浏览器上触发 XSS,其影响范围可能从烦人的弹出窗口到通过 cookie 劫持失去对其帐户的控制。
因此,我强烈建议不要设置通配符,除非它用于在页面上没有呈现任何内容的 API 端点。
您可以设置Access-Control-Allow-Headers: Pragma
为您的问题的替代解决方案。
请注意,*
对于没有凭据的请求(没有 HTTP cookie 或 HTTP 身份验证信息的请求),该值仅计为特殊的通配符值,否则它将被读取为文字标头。文档
在服务器尝试通过设置以下标头来完全禁用 CORS 的情况下。
Access-Control-Allow-Origin:*(告诉浏览器服务器接受来自任何 ORIGIN 的跨站点请求)
Access-Control-Allow-Credentials: true(告诉浏览器跨站请求可以发送cookies)
在浏览器中实现了故障保护,这将导致以下错误
"Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’"
因此,在大多数情况下,将“Access-Control-Allow-Origin”设置为*
不会有问题。然而,为了防止攻击,服务器可以维护一个允许的来源列表,并且每当服务器收到一个跨来源请求时,它可以根据允许的来源列表验证 ORIGIN 标头,然后在 Access-Control-Allow-Origin 中回显相同的内容标题。
由于浏览器上运行的 javascript 无法更改 ORIGIN 标头,因此恶意站点将无法对其进行欺骗。