C#如何忽略证书错误?

212
在对远程 Web 服务进行网络请求时,我收到了如下错误信息:

无法为 SSL/TLS 安全通道建立信任关系。---> System.Security.Authentication.AuthenticationException:根据验证程序,远程证书无效。

有没有什么方法可以忽略此错误并继续执行?
看起来远程证书未经签名。
我连接的站点是 www.czebox.cz - 您可以访问该站点并注意到即使浏览器也会抛出安全异常。
12个回答

423

添加证书验证处理程序。返回 true 将允许忽略验证错误:

ServicePointManager
    .ServerCertificateValidationCallback += 
    (sender, cert, chain, sslPolicyErrors) => true;

8
这比一开始看起来的还要更有用。我在使用托管Exchange Web Services (EWS)时遇到了OP的问题。我原以为不能使用这个答案,因为我没有访问由该托管库所发出的底层SOAP调用的权限。但是当我仔细再看一下时,我意识到ServicePointManager是独立存在的。所以,在初始化ExchangeService之前,我添加了上面的回调函数,它就像魔法一样奏效了。 - Mark Meuer
3
这是一个全局应用 bypass 的例子,适用于我们中的那些不良实践者。(有时你别无选择)http://jasig.275507.n4.nabble.com/NET-tip-for-dealing-with-bad-SSL-Certs-td2268566.html - snowYetis
1
非常感谢,这暂时解决了问题。请在Web Api的Startup.cs文件中添加此代码。 - Sivalingaamorthy
4
@MarkMeuer 差点放弃了解决我在 EWS API 问题上的方案,但是当我看到了你的评论时,情况就改变了。 - Mahen
15
@MiguelVeloso您当然可以自由地点踩,但请记住,问题和回答都没有讨论这个操作的安全性问题。主题明确是“如何忽略验证错误”,而不是“我们应该/不应该这样做”的问题,这是一个完全不同的话题。讨论为什么OP不应该这样做只会让事情变得更加混乱,正如评论者所指出的,有合理的情况下实际上可以这样做。因此,我们坚持主题并解决问题。 - Peter Lillevold
显示剩余8条评论

84

允许所有证书的做法非常强大,但也可能存在风险。如果您只想允许有效证书以及某些特定证书,可以按照以下方式操作。

.NET Core:

using (var httpClientHandler = new HttpClientHandler())
{
    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>
    {
        if (sslPolicyErrors == SslPolicyErrors.None)
        {
            return true;   //Is valid
        }

        if (cert.GetCertHashString() == "99E92D8447AEF30483B1D7527812C9B7B3A915A7")
        {
            return true;
        }
        return false;
    };

    using (var httpClient = new HttpClient(httpClientHandler))
    {
        var httpResponse = httpClient.GetAsync("https://example.com").Result;
    }
}

.NET Framework:

System.Net.ServicePointManager.ServerCertificateValidationCallback += delegate (
    object sender,
    X509Certificate cert,
    X509Chain chain,
    SslPolicyErrors sslPolicyErrors)
{
    if (sslPolicyErrors == SslPolicyErrors.None)
    {
        return true;   //Is valid
    }

    if (cert.GetCertHashString() == "99E92D8447AEF30483B1D7527812C9B7B3A915A7")
    {
        return true;
    }

    return false;
};

更新:

如何在 Chrome 中获取 cert.GetCertHashString() 的值:

点击地址栏中的 SecureNot Secure

然后点击证书 -> 详细信息 -> 指纹并复制该值。记得使用 cert.GetCertHashString().ToLower()


3
完全同意。这样可以跳过对(希望只有)一两个证书的检查,而不完全牺牲安全性。 - Kemuel Sanchez
我怎样可以从证书中获取“哈希字符串”? - Kiquenet
@Kiquenet 要么调试代码并从“立即窗口”运行cert.GetCertHashString(),要么在浏览器或本地安装了MMC的情况下检查证书的Thumbprint - Ogglas
服务器在我们的控制之下,生产环境中使用 @Ogglas 的代码仍然安全吗?使用 TLS/SSL,能够阻止中间人攻击吗? - Pingpong
.NET Core 的部分应该放在哪个类中,@Ogglas? - Kerollos Melad

33

IgnoreBadCertificates 方法:

//I use a method to ignore bad certs caused by misc errors
IgnoreBadCertificates();

// after the Ignore call i can do what ever i want...
HttpWebRequest request_data = System.Net.WebRequest.Create(urlquerystring) as HttpWebRequest;

/*
and below the Methods we are using...
*/

/// <summary>
/// Together with the AcceptAllCertifications method right
/// below this causes to bypass errors caused by SLL-Errors.
/// </summary>
public static void IgnoreBadCertificates()
{
    System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
}  

/// <summary>
/// In Short: the Method solves the Problem of broken Certificates.
/// Sometime when requesting Data and the sending Webserverconnection
/// is based on a SSL Connection, an Error is caused by Servers whoes
/// Certificate(s) have Errors. Like when the Cert is out of date
/// and much more... So at this point when calling the method,
/// this behaviour is prevented
/// </summary>
/// <param name="sender"></param>
/// <param name="certification"></param>
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns>true</returns>
private static bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
    return true;
} 

2
我不得不添加一行代码才能让它与我的代码配合使用(我正在使用websocket4net)。System.Net.ServicePointManager.CheckCertificateRevocationList = false;就在设置服务器证书验证回调之后。 - kalyanswaroop

26

它失败的原因不是因为它没有签名,而是因为您的客户端不信任根证书。与其关闭SSL验证,另一种方法是将根CA证书添加到应用程序信任的CA列表中。

这是您的应用程序目前不信任的根CA证书:

-----BEGIN CERTIFICATE-----
MIIFnDCCBISgAwIBAgIBZDANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJDWjEs
MCoGA1UECgwjxIxlc2vDoSBwb8WhdGEsIHMucC4gW0nEjCA0NzExNDk4M10xHjAc
BgNVBAMTFVBvc3RTaWdudW0gUm9vdCBRQ0EgMjAeFw0xMDAxMTkwODA0MzFaFw0y
NTAxMTkwODA0MzFaMFsxCzAJBgNVBAYTAkNaMSwwKgYDVQQKDCPEjGVza8OhIHBv
xaF0YSwgcy5wLiBbScSMIDQ3MTE0OTgzXTEeMBwGA1UEAxMVUG9zdFNpZ251bSBS
b290IFFDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoFz8yBxf
2gf1uN0GGXknvGHwurpp4Lw3ZPWZB6nEBDGjSGIXK0Or6Xa3ZT+tVDTeUUjT133G
7Vs51D6z/ShWy+9T7a1f6XInakewyFj8PT0EdZ4tAybNYdEUO/dShg2WvUyfZfXH
0jmmZm6qUDy0VfKQfiyWchQRi/Ax6zXaU2+X3hXBfvRMr5l6zgxYVATEyxCfOLM9
a5U6lhpyCDf2Gg6dPc5Cy6QwYGGpYER1fzLGsN9stdutkwlP13DHU1Sp6W5ywtfL
owYaV1bqOOdARbAoJ7q8LO6EBjyIVr03mFusPaMCOzcEn3zL5XafknM36Vqtdmqz
iWR+3URAUgqE0wIDAQABo4ICaTCCAmUwgaUGA1UdHwSBnTCBmjAxoC+gLYYraHR0
cDovL3d3dy5wb3N0c2lnbnVtLmN6L2NybC9wc3Jvb3RxY2EyLmNybDAyoDCgLoYs
aHR0cDovL3d3dzIucG9zdHNpZ251bS5jei9jcmwvcHNyb290cWNhMi5jcmwwMaAv
oC2GK2h0dHA6Ly9wb3N0c2lnbnVtLnR0Yy5jei9jcmwvcHNyb290cWNhMi5jcmww
gfEGA1UdIASB6TCB5jCB4wYEVR0gADCB2jCB1wYIKwYBBQUHAgIwgcoagcdUZW50
byBrdmFsaWZpa292YW55IHN5c3RlbW92eSBjZXJ0aWZpa2F0IGJ5bCB2eWRhbiBw
b2RsZSB6YWtvbmEgMjI3LzIwMDBTYi4gYSBuYXZhem55Y2ggcHJlZHBpc3UvVGhp
cyBxdWFsaWZpZWQgc3lzdGVtIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgYWNjb3Jk
aW5nIHRvIExhdyBObyAyMjcvMjAwMENvbGwuIGFuZCByZWxhdGVkIHJlZ3VsYXRp
b25zMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW
BBQVKYzFRWmruLPD6v5LuDHY3PDndjCBgwYDVR0jBHwweoAUFSmMxUVpq7izw+r+
S7gx2Nzw53ahX6RdMFsxCzAJBgNVBAYTAkNaMSwwKgYDVQQKDCPEjGVza8OhIHBv
xaF0YSwgcy5wLiBbScSMIDQ3MTE0OTgzXTEeMBwGA1UEAxMVUG9zdFNpZ251bSBS
b290IFFDQSAyggFkMA0GCSqGSIb3DQEBCwUAA4IBAQBeKtoLQKFqWJEgLNxPbQNN
5OTjbpOTEEkq2jFI0tUhtRx//6zwuqJCzfO/KqggUrHBca+GV/qXcNzNAlytyM71
fMv/VwgL9gBHTN/IFIw100JbciI23yFQTdF/UoEfK/m+IFfirxSRi8LRERdXHTEb
vwxMXIzZVXloWvX64UwWtf4Tvw5bAoPj0O1Z2ly4aMTAT2a+y+z184UhuZ/oGyMw
eIakmFM7M7RrNki507jiSLTzuaFMCpyWOX7ULIhzY6xKdm5iQLjTvExn2JTvVChF
Y+jUu/G0zAdLyeU4vaXdQm1A8AEiJPTd0Z9LAxL6Sq2iraLNN36+NyEK/ts3mPLL

-----END CERTIFICATE-----

你可以使用此证书解码器另一个证书解码器来对此证书进行解码和查看。


是的!这是我的情况,但我如何在Azure上添加证书,而不使用VM?我明天要尝试使用X509Store API,但任何信息在这里都受欢迎。 - João Antunes

18
绕过SSL证书....
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };

// Pass the handler to httpclient(from you are calling api)
var client = new HttpClient(clientHandler)

这是一个简化版的这个答案,没有添加任何新内容。 - Wai Ha Lee

8

在客户端配置中禁用SSL证书验证。

<behaviors>
   <endpointBehaviors>
      <behavior name="DisableSSLCertificateValidation">
         <clientCredentials>
             <serviceCertificate>
                <sslCertificateAuthentication certificateValidationMode="None" />
              </serviceCertificate>
           </clientCredentials>
        </behavior>

这是 web.config 吗?ASP.NET Core 有其他替代方案吗? - Shimmy Weitzhandler

7

这段代码对我有用。我必须添加TLS2,因为我感兴趣的URL正在使用它。

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback +=
    (sender, cert, chain, sslPolicyErrors) => { return true; };
using (var client = new HttpClient())
{
    client.BaseAddress = new Uri(UserDataUrl);
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new
      MediaTypeWithQualityHeaderValue("application/json"));
    Task<string> response = client.GetStringAsync(UserDataUrl);
    response.Wait();

    if (response.Exception != null)
    {
         return null;
    }

    return JsonConvert.DeserializeObject<UserData>(response.Result);
}

7

年代久远,但仍有用处...

实现相同行为的另一种好方法是通过配置文件(web.config)来实现。

 <system.net>
    <settings>
      <servicePointManager checkCertificateName="false" checkCertificateRevocationList="false" />
    </settings>
  </system.net>

注意:仅在.NET框架下测试通过。


这对我很有帮助。同时,它可以帮助QA/Dev团队进行测试,同时允许生产配置保持安全。谢谢 :) - Jeancarlo Fontalvo

4
这适用于 .Net Core。在 Soap 客户端上调用:
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication =
                new X509ServiceCertificateAuthentication()
                {
                    CertificateValidationMode = X509CertificateValidationMode.None,
                    RevocationMode = X509RevocationMode.NoCheck
                };  

2

如果您直接使用套接字并作为客户端进行身份验证,则服务点管理器回调方法将不起作用。以下是对我有效的内容。请仅用于测试目的

var activeStream = new SslStream(networkStream, false, (a, b, c, d) => { return true; });
await activeStream.AuthenticateAsClientAsync("computer.local");

关键在于在SSL流的构造函数中提供远程证书验证回调。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接