为什么大多数浏览器的预检请求中不包含TLS客户端证书? [英] Why is the TLS client certificate not being included in preflight request on most browsers?

查看:203
本文介绍了为什么大多数浏览器的预检请求中不包含TLS客户端证书?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建的Web应用程序有问题.该Web应用程序由一个有角度的4前端和一个dotnet核心RESTful API后端组成.要求之一是,需要使用SSL双向身份验证来验证对后端的请求.即客户证书.

I'm having an issue with a web app I'm building. The web app consists of an angular 4 frontend and a dotnet core RESTful api backend. One of the requirements is that requests to the backend need to be authenticated using SSL mutual authentication; i.e., client certificates.

当前,我同时将前端和后端托管为Azure应用服务,它们位于单独的子域中.

Currently I'm hosting both the frontend and the backend as Azure app services and they are on separate subdomains.

遵循此指南将后端设置为要求客户端证书,我认为这是针对Azure应用程序服务的唯一方法: https://docs.microsoft.com/zh-CN/azure/app-service/app-service-web-configure-tls-mutual-auth

The backend is set up to require client certificates by following this guide which I believe is the only way to do it for Azure app services: https://docs.microsoft.com/en-us/azure/app-service/app-service-web-configure-tls-mutual-auth

当前端向后端发出请求时,我将withCredentials设置为true - [根据文档] [1]也应与客户端证书一起使用.

When the frontend makes requests to the backend, I set withCredentials to true — which, [according to the documentation][1], should also work with client certificates.

XMLHttpRequest.withCredentials属性是一个布尔值,指示是否应使用cookie,授权标头或TLS客户端证书之类的凭据发出跨站点访问控制请求.设置withCredentials不会影响同一站点的请求.

The XMLHttpRequest.withCredentials property is a Boolean that indicates whether or not cross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates. Setting withCredentials has no effect on same-site requests.

前端的相关代码:

const headers = new Headers({ 'Content-Type': 'application/json' });
const options = new RequestOptions({ headers, withCredentials: true });

let apiEndpoint = environment.secureApiEndpoint + '/api/transactions/stored-transactions/';

return this.authHttp.get(apiEndpoint, JSON.stringify(transactionSearchModel), options)
    .map((response: Response) => {
         return response.json();
     })
     .catch(this.handleErrorObservable);

在Chrome上,此方法有效,当发出请求时,浏览器会提示用户输入证书,该证书将包含在预检请求中,并且一切正常.

On Chrome this works, when a request is made the browser prompts the user for a certificate and it gets included in the preflight request and everything works.

对于所有其他主要浏览器,情况并非如此. Firefox,Edge和Safari都失败了预检请求,因为服务器在请求中未包含客户端证书时会关闭连接.

For all the other main browsers however this is not the case. Firefox, Edge and Safari all fail the preflight request because the server shuts the connection when they don't include a client certificate in the request.

直接浏览到api端点会使每个浏览器提示用户输入证书,因此,我很确定这与大多数浏览器如何处理带有客户端证书的预检请求有关.

Browsing directly to an api endpoint makes every browser prompt the user for a certificate, so I'm pretty sure this is explicitly relevant to how most browsers handle preflight requests with client certificates.

做错什么了吗?还是其他浏览器通过发出请求时不提示输入证书来做错事?

Am doing something wrong? Or are the other browsers doing the wrong thing by not prompting for a certificate when making requests?

除了Chrome之外,我还需要支持其他浏览器,所以我需要以某种方式解决此问题.

I need to support other browsers than Chrome so I need to solve this somehow.

我已经看到通过让后端允许而不是要求证书来解决类似的问题.唯一的问题是,我还没有找到一种使用Azure应用程序服务实际执行此操作的方法.这是必需的还是不需要的.

I've seen similar issues being solved by having the backend allow rather than require certificates. The only problem is that I haven't found a way to actually do that with Azure app services. It's either require or not require.

有人对我的前进方式有什么建议吗?

Does anyone have any suggestions on how I can move on?

推荐答案

请参见 https://bugzilla.mozilla.org/show_bug.cgi?id=1019603 和我在

See https://bugzilla.mozilla.org/show_bug.cgi?id=1019603 and my comment in the answer at CORS with client https certificates (I had forgotten I’d seen this same problem reported before…).

所有要点是,您看到的差异的原因是Chrome中的错误.我已在 https://bugs.chromium .org/p/chromium/issues/detail?id = 775438 .

The gist of all that is, the cause of the difference you’re seeing is a bug in Chrome. I’ve filed a bug for it at https://bugs.chromium.org/p/chromium/issues/detail?id=775438.

问题在于Chrome浏览器未遵循此规范要求,该规范要求浏览器不要在预检请求中发送TLS客户端证书;因此Chrome会确实在飞行前发送您的TLS客户端证书.

The problem is that Chrome doesn’t follow the spec requirements on this, which mandate that the browser not send TLS client certificates in preflight requests; so Chrome instead does send your TLS client certificate in the preflight.

Firefox/Edge/Safari遵循规范要求,并且不要在起飞前发送TLS客户端证书.

Firefox/Edge/Safari follow the spec requirements and don’t send the TLS client cert in the preflight.

更新:在对问题的修改中添加的Chrome屏幕截图显示了OPTIONS请求和GET请求,以及随后的GET请求,而不是代码中的POST请求.因此,问题可能出在服务器禁止POST请求.

Update: The Chrome screen capture added in an edit to the question shows an OPTIONS request for a GET request, and a subsequent GET request — not the POST request from your code. So perhaps the problem is that the server forbids POST requests.

https://i.stack.imgur.com/GD8iG.png中显示的请求是CORS 预检OPTIONS请求浏览器会自动发送自己的内容,然后再尝试使用代码中的POST请求.

The request shown in https://i.stack.imgur.com/GD8iG.png is a CORS preflight OPTIONS request the browser automatically sends on its own before trying the POST request in your code.

代码中添加的Content-Type: application/json请求标头是触发浏览器发出预检OPTIONS请求的原因.

The Content-Type: application/json request header your code adds is what triggers the browser to make that preflight OPTIONS request.

重要的是要了解浏览器在预检中永远不会包含任何凭据.请求-请求发送到的服务器必须配置为对/api/transactions/own-transactions/OPTIONS请求不要求任何凭据/身份验证.

It’s important to understand the browser never includes any credentials in that preflight OPTIONS request — so the server the request is being sent to must be configured to not require any credentials/authentication for OPTIONS requests to /api/transactions/own-transactions/.

但是,来自 https://i.stack.imgur.com/GD8iG.png 似乎服务器禁止对该/api/transactions/own-transactions/OPTIONS请求.可能是因为请求缺少服务器期望的凭据,或者是因为服务器被配置为禁止所有OPTIONS请求,无论如何.

However, from https://i.stack.imgur.com/GD8iG.png it appears that server is forbidding OPTIONS requests to that /api/transactions/own-transactions/. Maybe that’s because the request lacks the credentials the server expects or maybe it’s instead because the server is configured to forbid all OPTIONS requests, regardless.

因此,结果是浏览器认为预检不成功,因此它就在那里停止,并且从不尝试从您的代码尝试POST请求.

So the result of that is, the browser concludes the preflight was unsuccessful, and so it stops right there and never moves on to trying the POST request from your code.

给出> https://i.stack.imgur.com/GD8iG.png中显示的内容很难理解它在Chrome中的实际效果如何-尤其是考虑到没有浏览器曾经发送过

Given what’s shown in https://i.stack.imgur.com/GD8iG.png it’s hard to understand how this could actually be working as expected in Chrome — especially given that no browsers ever send credentials of any kind in the preflight requests, so any possible browsers differences in handling of credentials would make no difference as far as the preflight goes.

这篇关于为什么大多数浏览器的预检请求中不包含TLS客户端证书?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆