【问题标题】:Why does the preflight OPTIONS request of an authenticated CORS request work in Chrome but not Firefox?为什么经过身份验证的 CORS 请求的预检 OPTIONS 请求在 Chrome 中有效,但在 Firefox 中无效?
【发布时间】:2013-03-21 23:19:26
【问题描述】:

我正在编写一个 JavaScript 客户端以包含在 3rd 方网站上(想想 Facebook 的 Like 按钮)。它需要从需要基本 HTTP 身份验证的 API 中检索信息。简化的设置如下所示:

第 3 方网站在其页面上包含此 sn-p:

<script 
async="true"
id="web-dev-widget"
data-public-key="pUbl1c_ap1k3y"
src="http://web.dev/widget.js">
</script>

widget.js 调用 API:

var el = document.getElementById('web-dev-widget'),
    user = 'token',
    pass = el.getAttribute('data-public-key'),
    url = 'https://api.dev/',
    httpRequest = new XMLHttpRequest(),
    handler = function() {
      if (httpRequest.readyState === 4) {
        if (httpRequest.status === 200) {
          console.log(httpRequest.responseText);
        } else {
          console.log('There was a problem with the request.', httpRequest);
        }
      }
    };

httpRequest.open('GET', url, true, user, pass);
httpRequest.onreadystatechange = handler;
httpRequest.withCredentials = true;
httpRequest.send();

API 已配置为使用适当的标头进行响应:

Header set Access-Control-Allow-Credentials: true
Header set Access-Control-Allow-Methods: "GET, OPTIONS"
Header set Access-Control-Allow-Headers: "origin, authorization, accept"
SetEnvIf Origin "http(s)?://(.+?\.[a-z]{3})$" AccessControlAllowOrigin=$0
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin

请注意,Access-Control-Allow-Origin 设置为 Origin,而不是使用通配符,因为我正在发送凭据请求 (withCredentials)。

现在一切就绪,可以发出异步跨域身份验证请求,并且在 OS X 10.8.2 上的 Chrome 25 中运行良好。在开发工具中,我可以看到OPTIONS 请求在GET 请求之前的网络请求,并且响应按预期返回。

在 Firefox 19 中测试时,Firebug 中没有出现对 API 的网络请求,并且在控制台中记录了此错误:NS_ERROR_DOM_BAD_URI: Access to restricted URI denied

经过大量挖掘,我发现Gecko doesn't allow the username and password to be directly in a cross-site URI根据cmets。我假设这是使用可选的用户和密码参数到open(),所以我尝试了另一种进行身份验证的请求的方法,即对凭据进行 Base64 编码并发送授权标头:

// Base64 from http://www.webtoolkit.info/javascript-base64.html
auth = "Basic " + Base64.encode(user + ":" + pass);

...
// after open() and before send()
httpRequest.setRequestHeader('Authorization', auth);

这导致401 UnauthorizedOPTIONS 请求的响应导致Google 搜索,例如“为什么这在Chrome 而不是Firefox 中有效!?”那时我知道我遇到了麻烦。

为什么 它在 Chrome 而不是 Firefox 中工作?如何让OPTIONS 请求一致地发送和响应?

【问题讨论】:

  • 我很想就如何使问题变得更好提供意见

标签: javascript ajax cors


【解决方案1】:

为什么 它在 Chrome 而不是 Firefox 中工作?

W3 spec for CORS preflight requests 明确指出应排除用户凭据。 ChromeWebKit 中存在一个错误,其中 OPTIONS 请求返回状态 401 仍会发送后续请求。

Firefox 有一个相关的错误提交,该错误以指向 W3 public webapps mailing list 的链接结尾,要求更改 CORS 规范以允许在 OPTIONS 请求上发送身份验证标头,这对 IIS 用户有利。基本上,他们正在等待那些服务器被淘汰。

我怎样才能让OPTIONS 请求始终如一地发送和响应?

只需让服务器(本例中为 API)响应 OPTIONS 请求,无需身份验证。

【讨论】:

  • 我应该始终对 OPTIONS 请求提供相同的响应,还是应该取决于请求的资源?如果它依赖于资源,攻击者可以使用 OPTIONS 请求来发现该资源支持的服务器内容/url 和功能。也请看这个问题:stackoverflow.com/questions/20805058/…
  • 不验证 OPTION 请求是否存在安全风险?
  • 对于那些在这里结束的人:值得使用curl -X OPTIONS http://yourdomain.example.com 来查看您的服务器对 OPTIONS 请求的响应。还要确保您完全清除浏览器缓存,Firefox 会主动缓存这些响应,因此即使您更改了服务器配置,它仍然会报告相同的错误。
  • 这对我来说是一个非常困难的发现过程。我不知道为什么花了这么长时间才找到这个答案,但了解“阻止 cookie 标志”以及它适用于“飞行前”帮助我理解 OPTIONS 请求不会发送 cookie .
  • 我真的很想回答@KevinMeredith 提出的问题......如果有的话,OPTIONS 请求不需要身份验证的安全风险是什么?
【解决方案2】:

这是一篇旧帖子,但也许这可以帮助人们完成 CORS 问题。要完成基本授权问题,您应该避免在服务器中对 OPTIONS 请求进行授权。这是一个 Apache 配置示例。只需在您的 VirtualHost 或 Location 中添加类似的内容。

<LimitExcept OPTIONS>
    AuthType Basic
    AuthName <AUTH_NAME>
    Require valid-user
    AuthUserFile <FILE_PATH>
</LimitExcept>

【讨论】:

  • 这是一个非常好的答案——谢谢!!!!!! --- sugest--- SetEnvIf Origin "^(.*?)$" origin_is=$0 标头始终设置 Access-Control-Allow-Origin %{origin_is}e env=origin_is
【解决方案3】:

这对我来说很特别。我正在发送一个名为“SESSIONHASH”的标头。 Chrome 和 Opera 没问题,但 Firefox 也希望在“Access-Control-Allow-Headers”列表中使用此标头。否则,Firefox 会抛出 CORS 错误。

【讨论】:

    猜你喜欢
    • 2014-09-07
    • 2014-09-03
    • 2021-05-07
    • 2021-08-30
    • 2014-01-15
    • 2023-03-14
    • 2016-12-16
    • 1970-01-01
    相关资源
    最近更新 更多