【问题标题】:C# verify server certificate with .pem fileC# 使用 .pem 文件验证服务器证书
【发布时间】:2020-11-30 13:33:06
【问题描述】:

我发现向启用 SSL 的 API 发送 http 请求时出现问题。 我得到的错误信息是 -

AuthenticationException: The remote certificate is invalid according to the validation procedure.

基于此请求

using (HttpResponseMessage res = client.GetAsync("https://example.com").Result)
            {
                using (HttpContent content = res.Content)
                {
                    string data = content.ReadAsStringAsync().Result;
                    if (data != null)
                    {
                        Console.WriteLine(data);
                    }
                    else
                    {
                        Console.WriteLine("Nothing returned");
                    }
                }
            }

我得到了一个 .pem 文件来验证发回的证书是否由我们的 CA 签名,并且在弄清楚如何在 C# 中执行此操作时遇到了一些麻烦

在 python 中,我可以通过将 .pem 文件传递​​给验证参数来解决证书错误,例如

r = requests.post(url="https://example.com", headers=headers, verify='mypem.pem') 

Dotnet Core 3 的 HttpClient 中是否有类似的东西?

感谢您的帮助!

【问题讨论】:

标签: c# ssl


【解决方案1】:

如果您出于某种原因无法将证书设置为受信任,那么您可以绕过证书验证并自行验证服务器。不幸的是,它在 .NET 中的优雅程度要低得多,而且这可能不适用于所有平台。有关更多讨论,请参阅bypass invalid SSL certificate in .net core 上的this answer

using (var httpClientHandler = new HttpClientHandler())
{
    // Override server certificate validation.
    httpClientHandler.ServerCertificateCustomValidationCallback = VerifyServerCertificate;
    // ^ if this throws PlatformNotSupportedException (on iOS?), then you have to use
    //httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
    // ^ docs: https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler.dangerousacceptanyservercertificatevalidator?view=netcore-3.0

    using (var client = new HttpClient(httpClientHandler))
    {
        // Make your request...
    }
}

我认为回调的这种实现可以满足您的需求,“固定”CA。从this answerForce HttpClient to trust single Certificate,还有更多来自我的cmets。 编辑:该答案的状态检查不起作用,但根据 Jeremy Farmer 链接的this answer,以下方法应该:

    static bool VerifyServerCertificate(HttpRequestMessage sender, X509Certificate2 certificate,
    X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        try
        {
            // Possibly required for iOS? :
            //if (chain.ChainElements.Count == 0) chain.Build(certificate);
            // https://forums.xamarin.com/discussion/180066/httpclienthandler-servercertificatecustomvalidationcallback-receives-empty-certchain
            // ^ Sorry that thread is such a mess!  But please check it.
            
            // Without having your PEM I am not sure if this approach to loading the cert works, but there are other ways.  From the doc:
            // "This constructor creates a new X509Certificate2 object using a certificate file name. It supports binary (DER) encoding or Base64 encoding."
            X509Certificate2 ca = new X509Certificate2("mypem.pem");

            X509Chain chain2 = new X509Chain();
            chain2.ChainPolicy.ExtraStore.Add(ca);

            // "tell the X509Chain class that I do trust this root certs and it should check just the certs in the chain and nothing else"
            chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;

            // This setup does not have revocation information
            chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

            // Build the chain and verify
            var isValid = chain2.Build(certificate);
            var chainRoot = chain2.ChainElements[chain2.ChainElements.Count - 1].Certificate;
            isValid = isValid && chainRoot.RawData.SequenceEqual(ca.RawData);

            Debug.Assert(isValid == true);

            return isValid;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }

        return false;
    }

抱歉,我目前无法对此进行测试,但希望对您有所帮助。

【讨论】:

  • 这很有帮助,不幸的是我无法让你上面的例子工作,ChainStatus 的长度最终总是为 0 并返回 false,这确实让我看到了这篇文章 - stackoverflow.com/a/50807130/12082289 使用该示例使我能够进行验证。谢谢你的帮助!如果您知道为什么链状态可能会以 0 的长度返回,请告诉我。我有兴趣让您的示例正常工作。
  • @JeremyFarmer 嗯。这是旧的(和复制的)代码。查看src of the ChainStatus stuff,并不清楚X509ChainStatusFlags.NoError 是否实际用于成功案例;看起来他们采用了“无状态 ==> 无错误”这一更简单的选项。这部分内部结构因平台而异,这有点超出我的理解范围......如果 Build(certificate) 返回 true,那么我认为你很好。
  • 我确实在别处读到“如果 ChainStatus.Length 为 0(无错误),或者如果 ChainStatus.Length > 0,但我们决定忽略所有这些错误,ChainPolicy.VerificationFlags 中有一些标志,则构建返回 TRUE 。”我将更新代码以匹配其他答案,请让我知道编辑是否与实际工作相匹配,以供后代使用。
  • 是的,你搞定了,编辑后的正是我最终得到的,非常感谢你的帮助!
猜你喜欢
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-08
相关资源
最近更新 更多