为什么经过身份验证的 CORS 请求的预检 OPTIONS 请求在 Chrome 中有效,但在 Firefox 中无效?

IT技术 javascript ajax cors
2021-01-15 14:45:21

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

第 3 方网站在其页面上包含此代码段:

<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 中运行良好。在 Dev Tools 中,我可以在OPTIONS请求之前看到请求的网络GET请求,并且响应按预期返回。

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

经过一番挖掘,根据评论发现Gecko不允许将用户名和密码直接放在跨站点URI中我认为这是使用可选的用户和密码参数,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);

这会导致对导致 Google 搜索401 UnauthorizedOPTIONS请求响应,例如“为什么这可以在 Chrome 而不是 Firefox 中工作!?” 那时我才知道我有麻烦了。

为什么没有它在Chrome和Firefox的不是工作?如何获得OPTIONS一致发送和响应请求?

3个回答

为什么没有它在Chrome和Firefox的不是工作?

CORS 预检请求W3 规范明确指出应排除用户凭据。ChromeWebKit存在一个错误,OPTIONS返回 401 状态的请求仍会发送后续请求。

Firefox提交了一个相关的错误,该错误以指向W3 公共 Web 应用程序邮件列表的链接结尾,该链接要求更改 CORS 规范,以允许在OPTIONS请求时发送身份验证标头,以造福 IIS 用户。基本上,他们正在等待这些服务器被淘汰。

如何获得OPTIONS一致发送和响应请求?

只需让服务器(在本例中为 API)响应OPTIONS请求而不需要身份验证。

Kinvey在扩展这方面做得很好,同时还链接到Twitter API 的一个问题,有趣地在任何浏览器问题被提交前几周概述了这个确切场景的 catch-22 问题。

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

这是一篇旧帖子,但也许这可以帮助人们完成 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 Header 总是设置 Access-Control-Allow-Origin %{origin_is}e env=origin_is
2021-03-17 14:45:21

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