如何在 C# 中进行双向 tls 身份验证

Posted

技术标签:

【中文标题】如何在 C# 中进行双向 tls 身份验证【英文标题】:How to do mutual tls authentication in C# 【发布时间】:2017-06-19 14:24:29 【问题描述】:

我有我的桌面应用程序。我想使用 C# 中的相互身份验证将发布请求发送到服务器 URL。我写了以下代码:--

System::Net::ServicePointManager::SecurityProtocol = SecurityProtocolType::Tls12;
WebRequestHandler ^ clientHandler = gcnew WebRequestHandler();
X509Certificates::X509Certificate2^ modCert = gcnew X509Certificates::X509Certificate2("Dev.pfx", "test");
clientHandler->ClientCertificates->Add(cerInter);
clientHandler->AuthenticationLevel = System::Net::Security::AuthenticationLevel::MutualAuthRequested;
clientHandler->ClientCertificateOptions = ClientCertificateOption::Manual;
httpClient = gcnew HttpClient(clientHandler);
HttpContent ^ httpContent = gcnew ByteArrayContent(state->postBody);
httpContent->Headers->ContentType = gcnew MediaTypeHeaderValue("application/octet-stream");
resultTask = httpClient->PostAsync(state->httpRequest, httpContent);

现在发布请求抛出异常,它是连接被远程主机强行关闭。我使用了wireshark,它显示客户端响应中的客户端证书长度为零。即使我没有在WebRequestHandler 中添加任何证书,我也会得到相同的响应。有人可以帮我解决这个问题或指导我寻找可能的解决方案。

Screenshot for wireshark

编辑

大家好,我发现了问题。我必须在本地商店中设置客户端证书。

X509Certificates::X509Store store(X509Certificates::StoreName::Root, X509Certificates::StoreLocation::LocalMachine);
            store.Open(X509Certificates::OpenFlags::ReadWrite);;
            store.Add(cerInter); 

但是,我面临的问题是,如果我不以管理员身份运行我的应用程序,则会引发访问权限异常。

如果我使用 StoreLocation::CurrentUser,它会弹出消息供批准。

有人可以建议,我如何在不提示消息的情况下将它与 StoreLocation::CurrentUser 一起使用?

除此之外,如果有人能提出建议,如果这是正确的方法,我将不胜感激?

【问题讨论】:

更多信息 - 我没有添加任何 web.config 文件。我不知道桌面应用程序是否需要它? 您示例中的代码是托管 C++,而不是 C#? 您好 Eric,感谢您的及时答复。是的,但我只在 C# 中使用过所有类。 我不确定你的意思。如果上面的托管 C++ 代码不是您遇到问题的代码,您可以分享您遇到问题的代码吗? 嗨,Eric,如果我让您感到困惑,我真的很抱歉....这是困扰我的托管 C++ 代码。我的想法是 HTTPclient 和 WebRequestHandler 都是 System.Net.HTTP 的一部分。因此,如果有人建议我用 C# 举一些例子,我可以很容易地用托管 C++ 编写相关代码... 【参考方案1】:

根据 Windows 的设计,您无法在没有提示的情况下将证书添加到每用户存储。您可以将证书添加到本地计算机存储,但仅在使用管理权限运行时。

您应该只需要将证书添加到用户的存储区一次(例如,在首次运行或设置期间)。

【讨论】:

感谢 Eric 的澄清。我需要您的一项建议/确认。是否必须在商店中设置证书以进行相互身份验证?我们可以不引导服务器查看添加到 WebRequestHandler 中的证书(在我的示例中它是 httpclient 的一部分)吗? 我不确定。 /可能/ SChannel(处理 HTTPS 握手的组件)要求将证书安装在当前用户的信任库中(例如,请参阅 Fiddler 配置说明:docs.telerik.com/fiddler/Configure-Fiddler/Tasks/…),以便私钥在正确的时间可用,但这似乎是一个非常蹩脚的限制。如果那(“WebRequest.ClientCertificates 中的证书是否必须首先安装到信任存储?”)是您正在寻找的答案,那么让问题更明确可能会有所帮助。 嗨,埃里克,对于令人困惑的问题,我深表歉意。让我重新表述我的问题 - 我正在从另一个组件获取证书。所以它不在磁盘中。现在对于 SSL 握手,当我调用 X509.Store 时,它​​会将其保存在本地系统的磁盘中。有没有办法避免将其保存在磁盘中?我试图在 httpclient 对象中设置两个证书,但服务器在握手时忽略了这一点。有什么方法可以要求服务器不要查看 X509Store(它在磁盘上)而是查看 httpclient 对象?

以上是关于如何在 C# 中进行双向 tls 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 LDAP over TLS 对 Active Directory 进行身份验证?

在 iOS 上使用智能卡进行 TLS 身份验证

双向身份验证如何如此瞬时?

如何使 SMTP 在 C# 中进行身份验证

使用 AWS API Gateway 进行客户端 TLS 身份验证

SSL和TLS协议如何提供身份验证机密性和完整性