为什么TLS客户端证书未包含在大多数浏览器的预检请求中?

为什么TLS客户端证书未包含在大多数浏览器的预检请求中?

问题描述:

我遇到了一个我正在构建的Web应用程序的问题。网络应用程序由一个角度4前端和一个dotnet核心RESTful api后端组成。其中一个要求是对后端的请求需要使用SSL相互认证进行认证;即客户证书。为什么TLS客户端证书未包含在大多数浏览器的预检请求中?

目前,我将前端和后端作为Azure应用服务托管,并且它们位于不同的子域中。

后端设置本指南,我相信是这样做对Azure的应用程序服务的唯一途径以下要求客户端证书: https://docs.microsoft.com/en-us/azure/app-service/app-service-web-configure-tls-mutual-auth

当前端发出请求到后端,我设置withCredentialstrue - 其中,[根据文档] [1],也应该与客户端证书一起工作。

XMLHttpRequest.withCredentials属性是一个布尔值,指示是否应使用诸如cookie,授权标头或TLS客户端证书之类的凭据来创建跨站点访问控制请求。使用Credentials进行设置对同一站点请求没有影响。从前端

相关代码:

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工作的,当一个请求时,浏览器会提示您输入证书的用户,它被包含在预检要求,一切工作。

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

直接浏览到api端点会使每个浏览器都提示用户输入证书,所以我非常确定这与大多数浏览器处理带有客户端证书的预检请求的方式明确相关。

我做错了什么?或者其他浏览器在提出请求时不提示证书,从而做错了事情?

我需要支持Chrome以外的其他浏览器,所以我需要以某种方式解决这个问题。

我见过类似的问题,通过让后端允许而不是要求证书来解决。唯一的问题是,我还没有找到一种方法来实际使用Azure应用服务来做到这一点。这是要求或不要求。

有没有人有任何建议我可以继续前进?

+0

请求是使用'XMLHttpRequest()'还是'fetch()'完成的? – guest271314

+0

如果请求在Chrome中按预期工作,请使用https://*.com/posts/46783506/edit编辑/更新问题并添加Chrome OPTIONS请求的请求和响应详细信息(因为问题已经存在用于Firefox请求)以及后续的POST请求。 – sideshowbarker

+0

@sideshowbarker你说得对,我用相关的屏幕大写更新了问题。 –

请参阅https://bugzilla.mozilla.org/show_bug.cgi?id=1019603和我在CORS with client https certificates答案中的评论(我忘记了我之前见过的同样的问题......)。

所有这一切的主旨,你所看到的差异的原因是Chrome中的一个错误。我在https://bugs.chromium.org/p/chromium/issues/detail?id=775438提交了一个bug。

问题在于Chrome不遵循此规范要求,该规定要求浏览器不在预检请求中发送TLS客户端证书;所以Chrome改为在预检时发送您的TLS客户端证书。

Firefox/Edge/Safari遵循规范要求,并且不要在预检时发送TLS客户端证书。


更新:在编辑的问题添加的镀铬屏幕截图显示了GET请求的OPTIONS请求,随后GET要求 - 而不是从你的代码POST请求。所以也许问题是服务器禁止POST请求。


https://i.stack.imgur.com/GD8iG.png显示的请求是CORS preflight OPTIONS request浏览器会自动尝试在代码中POST请求之前自行发送。

您的代码添加的Content-Type: application/json请求标头会触发浏览器进行预检OPTIONS请求。

了解浏览器是很重要的从来没有包括在预检OPTIONS要求任何credentials - 这样的请求被发送服务器必须配置为不需要任何凭证/认证为OPTIONS请求/api/transactions/own-transactions/

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

因此,结果是,浏览器得出结论,预检不成功,所以它停在那里,永远不会继续尝试从您的代码POST请求。

考虑什么https://i.stack.imgur.com/GD8iG.png所示的IT很难理解这个实际上可以按预期在浏览器 - 特别是考虑到没有浏览器曾经在预检请求发送credentials任何类型的,因此任何可能的浏览器中的凭证处理分歧会根据事先的情况,没有什么区别。

+0

感谢您的帖子。我想我了解CORS预检请求。但我猜Chrome实际上是罪魁祸首,并且通过在预检请求中包含TLS客户端证书也做错了事情。 服务器停止预检选项,因为它需要它没有得到的TLS客户端证书。我想唯一的解决方案是要么从saim子域提供请求,要么找到一种方法让Azure将客户端证书视为可选项,以便OPTIONS请求实际获得响应。 –

+0

我使用的解决方案之一是使用iframe和postMessage。适用于所有浏览器。 – nemke