【问题标题】:What security risks exist when setting Access-Control-Allow-Origin to accept all domains?设置 Access-Control-Allow-Origin 接受所有域存在哪些安全风险?
【发布时间】:2023-03-05 15:38:01
【问题描述】:

我最近不得不将 Access-Control-Allow-Origin 设置为 * 以便能够进行跨子域 AJAX 调用。我觉得这可能是一个安全问题。如果我保留该设置,我会面临哪些风险?

【问题讨论】:

  • 来自 JaffaTheCake 的答案 stackoverflow.com/a/56457665/441757 是正确的:“Access-Control-Allow-Origin: * 可以完全安全地添加到任何资源,除非该资源包含受保护的私有数据标准凭据以外的其他东西……cookie、HTTP 基本身份验证和 TLS 客户端证书。” 有关更多详细信息,请参阅stackoverflow.com/a/43154277/441757。只要您不在请求中包含凭据,Access-Control-Allow-Origin: * 就是安全的。如果您确实包含凭据,浏览器将不允许您执行Access-Control-Allow-Origin: *。安全。

标签: ajax security cors http-headers


【解决方案1】:

通过回复Access-Control-Allow-Origin: *,请求的资源允许与每个来源共享。这基本上意味着任何站点都可以向您的站点发送 XHR 请求并访问服务器的响应,如果您没有实现此 CORS 响应,情况就不会如此。

因此,任何网站都可以代表其访问者向您的网站发出请求并处理其响应。如果您实现了基于浏览器自动提供的某些内容(cookie、基于 cookie 的会话等)的身份验证或授权方案之类的实现,则第三方站点触发的请求也将使用它们。

这确实会带来安全风险,尤其是如果您不仅允许选定资源共享资源,而且还允许每个资源共享资源时。在这种情况下,您应该看看 When is it safe to enable CORS?

更新(2020-10-07)

如果Access-Control-Allow-Origin 设置为*,则当凭据模式设置为include 时,当前Fetch Standard 会省略凭据。

因此,如果您使用基于 cookie 的身份验证,则不会在请求中发送您的凭据。

【讨论】:

  • 如果你能举一个具体的例子说明共享身份验证访问如何带来安全风险,我会对此表示赞同。
  • @Gumbo 静态内容呢? (例如静态cdn内容,如javascripts、css、静态htmls等)在它们上设置Access-Control-Allow-Origin: *是否有任何安全问题?不会有nogin等,它们对所有人都是公开的?
  • 实际上,根据the current CORS standard,这个答案并不完全正确:“字符串'*'不能用于支持凭据的资源。”因此,您不能强制请求以 cookie、缓存的 HTTP 身份验证或客户端 SSL 证书的形式使用临时身份验证。但是,如果网站例如使用本地存储进行身份验证,那将是一个问题。
  • @NiklasB:我试过这个场景,Chrome 确实遵循你提到的 CORS 标准。即凭证请求不支持字符串“”。以下是 Chrome 报告的内容:“XMLHttpRequest 无法加载 localhost:12346/hello。当凭据标志为 true 时,不能在 'Access-Control-Allow-Origin' 标头中使用通配符 ''。来源 '@987654325 @' 因此不允许访问。XMLHttpRequest 的凭据模式由 withCredentials 属性控制。"
【解决方案2】:

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: *

【讨论】:

  • 应该“因为它只允许不带 cookie 的请求”是“因为它只允许带 cookie 的请求”吗?
  • @DJCordhose 没有。 Access-Control-Allow-Origin: * 只允许没有 cookie 的请求。我已经编辑了答案以澄清一点。
  • "*" 和没有这个标题的大小写有什么区别。是一样的吗?
  • 如果可以进一步解释“否则,一个糟糕的脚本可能会将您用作通往 Intranet 的隧道”,我会很高兴。
  • @SamRueby 说你去了我的邪恶页面,我可以调用运行在 你的 机器上的fetch('https://intranet.example.com/company-private-data'),并将结果发送回我的服务器。通过这样做,我已经使用您对 Intranet 的访问来读取 Intranet。
【解决方案3】:

AFAIK,Access-Control-Allow-Origin 只是从服务器发送到浏览器的 http 标头。将其限制在特定地址(或禁用它)不会使您的网站更安全,例如机器人。如果机器人愿意,他们可以忽略标题。默认情况下,常规浏览器(Explorer、Chrome 等)支持标题。但是像Postman 这样的应用程序会忽略它。

服务器端在返回响应时实际上并没有检查请求的“来源”是什么。它只是添加了 http 标头。发送请求的浏览器(客户端)决定读取访问控制标头并对其采取行动。请注意,在 XHR 的情况下,它可能会使用特殊的“OPTIONS”请求来首先请求标头。

因此,任何具有创造性脚本能力的人都可以轻松忽略整个标题,无论其中设置了什么。

另见Possible security issues of setting Access-Control-Allow-Origin


现在来实际回答问题

我不禁觉得我正在将我的环境置于安全状态 风险。

如果有人想攻击你,他们可以轻松绕过 Access-Control-Allow-Origin。但是通过启用“*”,您确实可以为攻击者提供更多“攻击向量”,例如使用支持该 HTTP 标头的常规网络浏览器。

【讨论】:

  • 从粗心的最终用户的角度来看这个。有人可以设置一个恶意网页,注入 JavaScript 以在真实站点和恶意站点之间传递数据(假设他们想窃取您的密码)。最终用户的网络浏览器通常会阻止这种跨站点通信,但如果设置了 Access-Control-Allow-Origin,那么它将被允许,最终用户不会更聪明。
  • 是的,强烈建议不要在托管脚本以窃取密码的恶意网站上设置 Access-Control-Allow-Origin * :-)
  • @commonpike 你是对的,因为有人可以制作一个脚本来完全忽略标题。如果数据可访问,则无论是否使用 CORS 标头都可以访问它。不过,您还没有考虑另一种攻击媒介。假设我登录银行的网站。如果我转到另一个页面然后返回我的银行,由于 cookie,我仍然在登录。互联网上的其他用户可以像我一样在我的银行访问相同的 URL,但是如果没有 cookie,他们将无法访问我的帐户。如果允许跨域请求,恶意网站可以有效地冒充...
  • @commonpike ...用户。换句话说,你可能只是访问我的网站(它甚至可以是一个普通网站,没有任何可疑之处......也许它是一个刚刚被劫持的真正合法网站!)但是一些 JavaScript 会向你的银行发出 HTTP 请求以转移一些资金到我的帐户。银行不知道来自其页面的请求与来自其他页面的请求之间的区别。两者都有使请求成功的 cookie。
  • @commonpike 让我给你举一个更常见的例子……一个经常发生的例子。假设你有一个普通的家用路由器,比如 Linksys WRT54g 什么的。假设路由器允许跨域请求。我网页上的脚本可以向常见的路由器 IP 地址(如192.168.1.1)发出 HTTP 请求,并重新配置您的路由器以允许攻击。它甚至可以将您的路由器直接用作 DDoS 节点。 (大多数路由器都有测试页面,允许 ping 或简单的 HTTP 服务器检查。这些可以被大量滥用。)
【解决方案4】:

当通配符确实有问题时,这里有 2 个以 cmets 形式发布的示例:

假设我登录银行的网站。如果我转到另一个页面然后 回到我的银行,因为 cookie,我仍然在登录。其他 互联网上的用户可以像我一样在我的银行访问相同的 URL,但是 如果没有 cookie,他们将无法访问我的帐户。如果 允许跨域请求,恶意网站可以有效 冒充用户。

——Brad

假设您有一个普通的家用路由器,例如 Linksys WRT54g 或 某物。假设路由器允许跨域请求。一个脚本 在我的网页上可以向普通路由器 IP 地址发出 HTTP 请求 (如 192.168.1.1)并重新配置您的路由器以允许攻击。它 甚至可以将您的路由器直接用作 DDoS 节点。 (大多数路由器都有 允许 ping 或简单的 HTTP 服务器检查的测试页面。这些 可以被大量滥用。)

——Brad

我觉得这些 cmets 应该是答案,因为他们用现实生活中的例子解释了问题。

【讨论】:

  • 除非这行不通。 “字符串 '*' 不能用于支持凭据的资源。” w3.org/TR/cors/#resource-requests
  • @bayotop 浏览器如何区分需要身份验证的页面和标题中包含其他数据的页面?
  • 阅读提供的链接后,有“支持凭据标志”用于此目的。它似乎是手动设置的,所以如果有人不知道如何正确设置 CORS,他们也可能会弄错这个标志,所以我相信上述漏洞是可能的。
  • @wedstrom 该标志由提出请求的人设置。无论如何,以上场景都是 CSRF 攻击的例子。允许 '*' 来源不会让你比现在更容易受到攻击(在极少数情况下可能会有点)。在大多数情况下,您可以使用表单发出恶意的跨站点请求,因此 CORS 无关紧要。在您需要执行 AJAX 请求的情况下,飞行前请求将会出现(这是当 ACAO: '*' 和 Access-Control-Allow-Credentials: 'true' 时浏览器进入的点)。
  • 关于这样的例子,像这样的扩展会有危险吗? chrome.google.com/webstore/detail/allow-cors-access-control/…其实我已经在我的一个小型网络应用中使用过它,我有安全方面的顾虑。
【解决方案5】:

此答案最初是作为对What are the security implications of setting Access-Control-Allow-Headers: *, if any? 的回复而写的,尽管与此问题无关,但已合并。


将其设置为通配符*,意味着允许除safelisted ones 之外的所有标头,并删除确保它们安全的限制。

这些是被认为是安全的 4 个安全列表标头的限制:

  • 对于 Accept-Language 和 Content-Language:只能具有由 0-9A-Za-z、空格或 *,-.;= 组成的值。
  • 对于 Accept 和 Content-Type:不能包含 CORS 不安全的请求标头字节:0x00-0x1F0x09 (HT) 除外,这是允许的)、"():<>?@[\]{}0x7F(DEL )。
  • 对于 Content-Type:需要其解析值(忽略参数)的 MIME 类型为 application/x-www-form-urlencodedmultipart/form-datatext/plain
  • 对于任何标头:值的长度不能大于 128。

为简单起见,我将根据这些标题来回答。

根据服务器实现,简单地删除这些限制可能非常危险(对用户而言)。
例如,this outdated wordpress plugin 有一个反射型 XSS 漏洞,其中Accept-Language 的值被解析并按原样呈现在页面上,如果值中包含恶意负载,则会导致用户浏览器上的脚本执行。

使用通配符标头Access-Control-Allow-Headers: *,重定向到您网站的第三方网站可以将标头的值设置为Accept Language: <script src="https://example.com/malicious-script.js"></script>,因为通配符消除了上述第1点中的限制。

然后,预检响应会为此请求开绿灯,并且用户将被重定向到您的网站,从而在他们的浏览器上触发 XSS,其影响范围可能从烦人的弹出窗口到通过 cookie 劫持失去对其帐户的控制。

因此,我强烈建议不要设置通配符,除非它用于在页面上没有呈现任何内容的 API 端点。

您可以将Access-Control-Allow-Headers: Pragma 设置为您的问题的替代解决方案。


请注意,* 的值仅被视为没有凭据的请求(没有 HTTP cookie 或 HTTP 身份验证信息的请求)的特殊通配符值,否则它将被读取为文字标头。 Documentation

【讨论】:

    【解决方案6】:

    在服务器尝试通过设置以下标头来完全禁用 CORS 的情况。

    • Access-Control-Allow-Origin: *(告诉浏览器服务器接受 来自任何 ORIGIN 的跨站点请求)

    • Access-Control-Allow-Credentials: true(告诉浏览器跨 站点请求可以发送cookie)

    在浏览器中实现了故障保护,这将导致以下错误

    "Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’"
    

    所以在大多数情况下,将“Access-Control-Allow-Origin”设置为* 不会有问题。然而,为了防止攻击,服务器可以维护一个允许的来源列表,并且每当服务器收到一个跨来源请求时,它可以根据允许的来源列表验证 ORIGIN 标头,然后在 Access-Control-Allow-Origin 中回显相同的内容标题。

    由于浏览器上运行的 javascript 无法更改 ORIGIN 标头,因此恶意网站将无法对其进行欺骗。

    【讨论】:

      猜你喜欢
      • 2019-08-19
      • 2013-02-05
      • 2016-11-09
      • 2014-01-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多