【问题标题】:CORS with client https certificates带有客户端 https 证书的 CORS
【发布时间】:2017-04-01 12:16:17
【问题描述】:

我有一个带有两个 https 服务器的站点。一个(前端)提供由静态页面组成的 UI。另一个(后端)提供微服务。他们俩碰巧都使用相同的(测试)X509 证书来标识自己。单独来说,我可以通过需要客户端证书“tester”的 https 连接到它们。

到目前为止,我们一直在通过 nginx 设置来隐藏 CORS 问题,该设置使前端和后端看起来是相同的 Origin。我已经为所有请求实现了标题“Access-Control-Allow-Origin”、“Access-Control-Allow-Credentials”;带有用于预检检查请求的方法、标头 (OPTIONS)。

  • 在 Chrome 中,像这样的跨站点可以正常工作。我可以看到前端 URL 和后端 URL 是不同的站点。我看到在发出后端请求之前发出了 OPTIONS 请求。

  • 尽管 Chrome 似乎不需要它,但我确实找到了将用于执行请求的 xmlhttprequest 对象并在其上执行了xhr.withCredentials = true,因为这似乎是 fetch.js 在幕后所做的当它得到"credentials":"include"。我注意到有一个可用的 xhr.setRequestHeader 函数,我可能需要使用它来让 Firefox 开心。

    • Firefox 的 UI 调用行为相同。但是对于所有后端调用,我得到一个 405。当它这样做时,没有与服务器建立网络连接。浏览器只是决定这是一个 405 而不执行任何 https 请求。尽管这与 Chrome 的行为不同,但它是有道理的。前端 UI 和后端服务都需要选择客户端证书。当我连接到 UI 时,我选择了证书“tester”。当它发出后端请求时,它可以假设应该使用相同的客户端证书来到达后端。但也许它假设它可能会有所不同,我还需要告诉 Firefox。

这里有没有人使用 CORS 和这样的 2 路 SSL 证书,并且遇到了这个 Firefox 问题并在某个地方修复了它。我怀疑这不是服务器端修复,而是客户端需要做的事情。

【问题讨论】:

  • 你在 Safari 中测试过吗?边缘?知道他们在这方面与 Firefox 匹配会很有趣。这可能是您看到的仅在 Chrome 中发生的行为。 Firefox 的行为似乎符合当前规范。
  • 我遇到了同样的问题,我们也使用 2-way SSL 设置。除了我没有得到任何状态码——Firefox 只是中止了 ajax 调用。你有没有解决过这个问题?
  • 基本上,这是一个错误,它甚至可以在 Chrome 中运行。规范说 OPTION 动词在发出请求时不应使用客户端证书。如果您拒绝没有客户端证书的所有连接,那么您将永远无法获得 OPTIONS 请求。您可以让 nginx 为您发回 200 并阻止您的服务看到 OPTION。这就是我要尝试的方法,因为如果 CORS 不可移植,它几乎毫无用处。 bugzilla.mozilla.org/show_bug.cgi?id=1019603#c9
  • 规范要求的问题是浏览器在发送请求之前就知道它是什么类型的请求,但是服务器直到 TLS协商之后才知道
  • 我为此提出了bugs.chromium.org/p/chromium/issues/detail?id=775438(几年前)。 Chrome 的行为尚未更改,尽管该错误中的 cmets 表明他们确实打算更改它。

标签: https cors pki


【解决方案1】:

将 CORS 与凭据(基本身份验证、cookie、客户端证书等)一起使用时:

  • Access-Control-Allow-Credentials 必须true
  • Access-Control-Allow-Origin 不得*
  • Access-Control-Allow-Origin 不得是多值(既不重复也不以逗号分隔)
  • Access-Control-Allow-Origin 必须设置为与请求的 Origin 标头完全相同的值,以使请求能够工作(以这种方式进行硬编码,或者如果它通过允许值的白名单)李>
  • 预检 OPTIONS 请求不得需要凭据(包括客户端证书)。预检的部分目的是询问 CORS 请求中允许的内容,因此在知道是否允许之前发送凭据是不正确的。
  • 预检 OPTIONS 请求必须返回 200 级响应,一般为 204

注意:对于 Access-Control-Allow-Origin,您可能需要考虑允许值 null,因为重定向链(如通常用于 OAuth 的链)可能会导致来自浏览器的请求中出现 Origin 值。

【讨论】:

  • 您是否真的在不同的浏览器中尝试过?我最后一次尝试这个是大约 2 年前。它适用于带有 PKI 客户端证书的 Chrome。它不适用于 Firefox 或 Safari。这是因为规范说如果您使用证书进行身份验证,它不会在 OPTIONS 请求期间发送 DN。并且由于该 mTLS 连接将无法到达后端。它在 Chrome 中工作的原因是它们(正确地恕我直言)违反了规范,以使功能正常工作。自从我上次调查以来,它可能已经改变了。
  • 是的。我们在 Chrome、Firefox、IE、Safari 和 Edge 中工作(大约 7-8 年)。有一些方法可以将 Apache HTTPD 和 Nginx 配置为不需要客户端验证 OPTIONS 请求,并且如果未提供证书,则将任何非 OPTIONS 处理为 403。不建议在 Chrome 中对此进行主要测试,因为您是正确的,为了方便起见,它违反了规范。
  • 啊。在我们的例子中,我们需要 mTLS。如果你没有被识别,边缘根本不会转发到后端。这是在 http 解析甚至可以开始之前。不幸的是,由于 TLS 在 http 上的分层方式,有很多服务器都是这样工作的。
  • 您不能在边缘执行 CORS 吗?这就是我们所做的一切。如果你想这样做的话,至少应该可以在边缘处理 OPTIONS 并让所有其他的都由你的后端处理。
【解决方案2】:

我实际上并没有使用客户端证书对此进行过测试,但我似乎记得如果将Access-Control-Allow-Origin 设置为* 通配符而不是实际域,Firefox 将不会发送凭据。请参阅 MDN 上的 this page

此外,Firefox 将 CORS 请求发送到期望客户端证书在 TLS 握手中呈现的服务器也存在问题。基本上,Firefox 不会在预检期间发送证书,从而产生先有鸡还是先有蛋的问题。请参阅 bugzilla 上的 this bug

【讨论】:

  • Chrome 提交者bugzilla.mozilla.org/show_bug.cgi?id=1019603#c9 的评论表明这里的错误实际上是在 Chrome 中,并且 Firefox 行为是当前规范所要求的。因此,了解 Safari 和 Edge 在这里做了什么会很有趣。
  • 确实如此。如果事实证明 Firefox 的解释是正确的,那么如何在后端实现客户端证书身份验证?也许通过使用匿名 SSL 进行初始连接,然后在预检后重新协商?我不确定这是否可行。
  • 这是问题的正确答案。浏览器行为差异的原因只是 Chrome 中的一个错误。 Firefox、Edge 和 Safari 都符合规范的要求——也就是说,它们在预检请求中不包含 SSL/TLC 客户端证书。请参阅stackoverflow.com/questions/46783506/…的相关答案
  • 不可能认真考虑 Firefox 的行为。一个需要 2-way auth 的 TLS 连接得到建立,一个 http 协议层在其中运行。更具体地说,它将类似于 nginx 服务器,在任何情况下都不会将未经身份验证的请求转发到其背后的微服务;出于审计原因。无论规范怎么说,Chrome 的行为都是正确的。
  • 我同意 Chrome 处理此问题的方式可能更适合此类用例,但遵循规范也很重要。我不认为他们在编写 CORS 规范时考虑到了这种情况,因此对这种情况进行修改以考虑预检请求中的故意身份验证可能是更正确的解决方案。
猜你喜欢
  • 1970-01-01
  • 2017-01-02
  • 1970-01-01
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 2019-05-13
  • 2018-03-15
  • 2011-12-10
相关资源
最近更新 更多