gpt4 book ai didi

C#/.NET - 如何在我的应用程序中允许 HTTPS 的 "custom"Root-CA(仅)?

转载 作者:可可西里 更新时间:2023-11-01 07:56:04 25 4
gpt4 key购买 nike

好的,这是我需要做的:

我的应用程序是用 C# (.NET Framework 4.5) 编写的,需要通过 HTTPS 与我们的服务器通信。我们的服务器使用我们自己的 Root-CA 颁发的 TLS/SSL 证书。该 Root-CA 虽然完全受我的应用程序信任,但安装在系统的“受信任的根”证书库中。因此,如果没有进一步的工作,C# 将拒绝联系服务器,因为无法验证服务器的证书 - 正如预期的那样。注意:我们不能使用系统中已经安装的 Root-CA。

我该怎么做才能让我的应用程序(安全地)联系我们的服务器?我知道 C# 提供了将我们的 Root-CA 证书作为“受信任的根”安装到系统证书库中的类。这不是我们想要做的!那是因为 (a) 它向用户显示了一个令人震惊的(并且技术性太强的)警告,并且因为 (b) 它也会影响其他应用程序 - 我们不会这样做不想也不需要。

所以我需要的是告诉 C#/.NET 使用“自定义”(即 特定于应用程序)的证书集 - 而不是系统范围的证书存储 - 来验证服务器证书链。整个证书链仍然需要正确验证(包括吊销列表!)。只有我们的根 CA 需要被接受为我的应用程序的“可信”根。

执行此操作的最佳方法是什么?

任何帮助将不胜感激。提前致谢!


顺便说一句:我发现我可以使用 ServicePointManager.ServerCertificateValidationCallback 来安装我自己的证书验证功能。这确实有效。但这种方法并不好,因为现在我需要在我自己的代码中手动整个证书验证。但是,我想要重新实现整个证书验证过程(例如下载和检查 CRL 等),该过程已经在 .NET Framework 中实现(和测试)。这就像重新发明轮子,永远无法像已经存在的 .NET 实现那样进行彻底的测试。

最佳答案

RemoteCertificateValidationCallback 委托(delegate)是解决问题的正确方法。但是,我会在委托(delegate)中使用不同于 Olivier 建议的行为。这就是为什么:执行了太多不相关的检查而没有执行相关的检查。

那么,详细看问题:

首先,我们将考虑当您的服务使用从商业 CA 购买的合法证书时的场景(现在可能不是这种情况,但将来可能是这种情况)。这意味着如果 sslPolicyErrors 参数有 None 标志,立即返回 True,证书有效并且没有明显的理由拒绝它。仅当以下声明不严格时才需要此步骤:

Only our Root-CA needs to be accepted as a "trusted" root for my application.

否则,忽略第一步。

让我们假设,该服务仍然使用来自私有(private)和不受信任的 CA 的证书。在这种情况下,我们必须处理与证书链无关且仅特定于 SSL session 的错误。因此,当调用 RemoteCertificateValidationCallback 委托(delegate)时,我们应确保 RemoteCertificateNameMismatchRemoteCertificateNotAvailable 标志不会出现在 sslPolicyErrors 参数。如果出现其中任何一个,我们将拒绝连接而不进行额外检查。

让我们假设没有出现这些标志。此时我们正确地处理了特定于 SSL 的错误,只有证书链可能有问题。

如果我们做到这一点,我们可以声明 sslPolicyErrors 参数包含 RemoteCertificateChainErrors 标志。这可能意味着一切,我们必须进行额外的检查。您的根 CA 证书是一个常量。这意味着我们可以检查 chain 参数中的根证书并将其与我们的常量(例如根 CA 证书的指纹)进行比较。如果比较失败,我们会立即拒绝该证书,因为它不是您的并且没有明显的理由信任由未知 CA 颁发的证书并且可能存在其他链问题。

如果比较成功,那么我们就到了必须谨慎妥善处理的情况。我们必须执行证书链引擎的另一个实例并指示它收集任何链问题,仅 UntrustedRoot 错误除外。这意味着如果 SSL 证书有其他问题(例如 RevocationOffline、有效性、策略错误),我们将知道并拒绝该证书。

下面的代码是上面许多词的编程实现:

using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace MyNamespace {
class MyClass {
Boolean ServerCertificateValidationCallback(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
String rootCAThumbprint = ""; // write your code to get your CA's thumbprint

// remove this line if commercial CAs are not allowed to issue certificate for your service.
if ((sslPolicyErrors & (SslPolicyErrors.None)) > 0) { return true; }

if (
(sslPolicyErrors & (SslPolicyErrors.RemoteCertificateNameMismatch)) > 0 ||
(sslPolicyErrors & (SslPolicyErrors.RemoteCertificateNotAvailable)) > 0
) { return false; }
// get last chain element that should contain root CA certificate
// but this may not be the case in partial chains
X509Certificate2 projectedRootCert = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
if (projectedRootCert.Thumbprint != rootCAThumbprint) {
return false;
}
// execute certificate chaining engine and ignore only "UntrustedRoot" error
X509Chain customChain = new X509Chain {
ChainPolicy = {
VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority
}
};
Boolean retValue = customChain.Build(chain.ChainElements[0].Certificate);
// RELEASE unmanaged resources behind X509Chain class.
customChain.Reset();
return retValue;
}
}
}

此方法(命名委托(delegate))可以附加到 ServicePointManager.ServerCertificateValidationCallback。代码可能会被压缩(例如,在一个 IF 语句中组合多个 IF),我使用冗长的版本来反射(reflect)文本逻辑。

关于C#/.NET - 如何在我的应用程序中允许 HTTPS 的 "custom"Root-CA(仅)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33627593/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com