ssl时如何忽略证书检查


132

我正在尝试找到一种在请求Https资源时忽略证书检查的方法,到目前为止,我在Internet上找到了一些有用的文章。

但是我仍然有一些问题。请检查我的代码。我只是不明白代码ServicePointManager.ServerCertificateValidationCallback是什么意思。

什么时候调用此委托方法?还有一个问题,我应该在哪里写这段代码?在ServicePointManager.ServerCertificateValidationCallback执行之前还是之前Stream stream = request.GetRequestStream()

public HttpWebRequest GetRequest()
{
    CookieContainer cookieContainer = new CookieContainer();

    // Create a request to the server
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_remoteUrl);

    #region Set request parameters

    request.Method = _context.Request.HttpMethod;
    request.UserAgent = _context.Request.UserAgent;
    request.KeepAlive = true;
    request.CookieContainer = cookieContainer;
    request.PreAuthenticate = true;
    request.AllowAutoRedirect = false;

    #endregion

    // For POST, write the post data extracted from the incoming request
    if (request.Method == "POST")
    {
        Stream clientStream = _context.Request.InputStream;
        request.ContentType = _context.Request.ContentType;
        request.ContentLength = clientStream.Length;

        ServicePointManager.ServerCertificateValidationCallback = delegate(
            Object obj, X509Certificate certificate, X509Chain chain, 
            SslPolicyErrors errors)
            {
                return (true);
            };

            Stream stream = request.GetRequestStream();

            ....
        }

        ....

        return request;
    }
}   

Answers:


67

由于只有一个全局ServicePointManager,因此设置ServicePointManager.ServerCertificateValidationCallback将产生以下结果:所有后续请求都将继承此策略。由于它是全局“设置”,因此最好在Global.asaxApplication_Start方法中进行设置。

设置回调将覆盖默认行为,您可以自己创建自定义验证例程。


对于没有Global.asax的客户端该怎么办?我正在调用从手持设备在本地网络上运行的REST服务。
B. Clay Shannon

3
该问题特定于HttpWebRequest。如果您使用任何其他方式,则必须查看文档中如何完成此操作。
Sani Singh Huttunen 2014年

我正在使用WebRequest,它将被强制转换为HttpWebRequest,例如:((HttpWebRequest)request).Accept = contentType;
B. Clay Shannon

如我的回答所述:最好在Global.asax中设置它不是必需的。您甚至可以在调用REST服务之前进行设置。
Sani Singh Huttunen 2014年

3
请参阅此链接以获取可能的解决方案。
Sani Singh Huttunen 2014年

174

对于有兴趣按每个请求应用此解决方案的任何人,这是一个选择,并使用Lambda表达式。同样的Lambda表达式也可以应用于blak3r提到的全局过滤器。此方法似乎需要.NET 4.5。

String url = "https://www.stackoverflow.com";
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
request.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

在.NET 4.0中,Lambda表达式可以这样应用于全局过滤器

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

2
FtpWebRequest是否有按请求的解决方案?
Timo 2015年

它似乎存在于我的4.0罚款
NACHT

我认为到目前为止,这是对“全局”变体的更好解决方案,尽管我当然可以理解您为什么想要它。我个人更喜欢一个请求工厂,然后由它管理此验证回调。谢谢亚当,很好的解决方案。
参议员

2
true在开发过程中进行实验时,可以做返回操作,但这并不安全。它应该是有条件的。
弗雷德(Fred)

1
使用(HttpWebRequest)WebRequest.Create(url)是完全有效的方法,但在我看来,HttpWebRequest.Create(url)仍然存在于面向.Net 4.6.2的项目中。Chef的选择,但此时HttpClient可能是更好使用的API。
亚当·威尼西亚

53

这对我有用:

System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                        System.Security.Cryptography.X509Certificates.X509Chain chain,
                        System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        return true; // **** Always accept
    };

此处的摘录:http : //www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors


17
ServicePointManager.ServerCertificateValidationCallback + =(发件人,证书,链,sslPolicyErrors)=> true;
David Rutgos 2014年

3
始终返回true是不安全的。它应该有条件地返回true。
弗雷德(Fred)

这是每个过程,因此不安全。
米哈伊尔·奥尔洛夫

25

还有一个简短的委托解决方案:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 

3
总是返回true是不安全的。
弗雷德(Fred)

7
是的,根据定义,始终信任所有SSL证书都是不安全的。尽可能避免这样做。
Andrej Rommel

@AndrejRommel您推荐什么方式?
Kiquenet

2
推荐的方法是创建有效的SSL证书,并在可以控制服务器的情况下正确使用它。我们最终使用letsencrypt.org创建了一个。
安德烈·隆梅尔

5

有人提到,在.NET 4.5之前,访问它的请求上的属性ServicePointManager不可用。

这是.NET 4.0代码,可让您ServicePoint根据每个请求进行访问。它没有使您可以访问每个请求的回调,但是应该可以让您找到有关该问题的更多详细信息。只需访问scvPoint.Certificate(或ClientCertificate如果您愿意)属性。

WebRequest request = WebRequest.Create(uri);

// oddity: these two .Address values are not necessarily the same!
//  The service point appears to be related to the .Host, not the Uri itself.
//  So, check the .Host vlaues before fussing in the debugger.
//
ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);
if (null != svcPoint)
{
    if (!request.RequestUri.Host.Equals(svcPoint.Address.Host, StringComparison.OrdinalIgnoreCase))
    {
        Debug.WriteLine(".Address              == " + request.RequestUri.ToString());
        Debug.WriteLine(".ServicePoint.Address == " + svcPoint.Address.ToString());
    }
    Debug.WriteLine(".IssuerName           == " + svcPoint.Certificate.GetIssuerName());
}

同意!但是,此操作规范是关于如何操作ignore它们,而不是信任它们。
杰西·奇斯霍尔姆

无论如何,使用ServicePointI 无法 始终信任所有SSL证书,也不忽略所有证书,因为尚未ServerCertificateValidationCallback 在ServicePoint中进行委派
Kiquenet

4

顺便说一句,这是在我知道的给定应用程序中关闭所有证书验证的最不冗长的方法:

ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;

4

您可以在HttpClient的本地实例上设置回调,而不是向ServicePointManager添加回调以全局替代证书验证。此方法应仅影响使用该HttpClient实例进行的调用。

以下示例代码显示了如何在Web API控制器中实现忽略特定服务器的证书验证错误。

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

public class MyController : ApiController
{

    // use this HttpClient instance when making calls that need cert errors suppressed
    private static readonly HttpClient httpClient;

    static MyController()
    {
        // create a separate handler for use in this controller
        var handler = new HttpClientHandler();

        // add a custom certificate validation callback to the handler
        handler.ServerCertificateCustomValidationCallback = ((sender, cert, chain, errors) => ValidateCert(sender, cert, chain, errors));

        // create an HttpClient that will use the handler
        httpClient = new HttpClient(handler);
    }

    protected static ValidateCert(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
    {

        // set a list of servers for which cert validation errors will be ignored
        var overrideCerts = new string[]
        {
            "myproblemserver",
            "someotherserver",
            "localhost"
        };

        // if the server is in the override list, then ignore any validation errors
        var serverName = cert.Subject.ToLower();
        if (overrideCerts.Any(overrideName => serverName.Contains(overrideName))) return true;

        // otherwise use the standard validation results
        return errors == SslPolicyErrors.None;
    }

}

这不是仅适用于.NET Core吗?(或者每当ServerCertificateCustomValidationCallback添加到HttpClientHandler时)?
phillyslick

此解决方案应在.Net Framework 4.5和更高版本以及.Net Core中运行(尽管我尚未在.Net Core中对其进行测试)。
谢尔顿

@Sheldon,这是一颗宝石:)成功用于.net和.net核心应用程序之间的localhost api调用中。好的解决方法,不接受所有方法。

3

根据亚当的回答和罗布的评论,我使用了以下方法:

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => certificate.Issuer == "CN=localhost";

过滤掉“忽略”。当然,可以根据需要添加其他发行人。由于我们需要支持一些旧代码,因此已在.NET 2.0中进行了测试。


@karank抱歉,您无法回复-可以在实际通话之前将其添加到任何位置,例如。在调用request.GetResponse()之前。请注意,虽然您的情况下,发行方可能还包含其他内容。
Andrej Grobler 2014年

3

CA5386:漏洞分析工具将提醒您这些代码。

正确的代码:

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
{
   return (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != SslPolicyErrors.RemoteCertificateNotAvailable;
};

3

对于.net core

using (var handler = new HttpClientHandler())
{ 
    // allow the bad certificate
    handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => true;
    using (var httpClient = new HttpClient(handler))
    {
        await httpClient.PostAsync("the_url", null);
    }
}

2

明确表示...

ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(CertCheck);

private static bool CertCheck(object sender, X509Certificate cert,
X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
    return true;
}

0

除了Sani和blak3r的答案外,我还在我的应用程序的启动代码中添加了以下内容,但在VB中:

'** Overriding the certificate validation check.
Net.ServicePointManager.ServerCertificateValidationCallback = Function(sender, certificate, chain, sslPolicyErrors) True

似乎可以解决问题。


0

提示:您还可以使用此方法来跟踪即将到期的证书。如果您发现即将过期的证书,并且可以及时进行修复,则可以节省培根。对第三方公司也很有利-对我们来说这是DHL / FedEx。DHL只是让证书过期,这让我们在感恩节前三天搞砸了。幸运的是,这次我要修复它!

    private static DateTime? _nextCertWarning;
    private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
    {
        if (error == SslPolicyErrors.None)
        {
            var cert2 = cert as X509Certificate2;
            if (cert2 != null)
            { 
                // If cert expires within 2 days send an alert every 2 hours
                if (cert2.NotAfter.AddDays(-2) < DateTime.Now)
                {
                    if (_nextCertWarning == null || _nextCertWarning < DateTime.Now)
                    {
                        _nextCertWarning = DateTime.Now.AddHours(2);

                        ProwlUtil.StepReached("CERT EXPIRING WITHIN 2 DAYS " + cert, cert.GetCertHashString());   // this is my own function
                    }
                }
            }

            return true;
        }
        else
        {
            switch (cert.GetCertHashString())
            {
                // Machine certs - SELF SIGNED
                case "066CF9CAD814DE2097D367F22D3A7E398B87C4D6":    

                    return true;

                default:
                    ProwlUtil.StepReached("UNTRUSTED CERT " + cert, cert.GetCertHashString());
                    return false;
            }
        }
    }

确保处理您的警报机制可能具有过期的证书的情况-否则最终将导致stackoverflow!
Simon_Weaver

什么ProwlUtil.StepReached
Kiquenet

抱歉,这只是我自己的调用Prowl API的方法,该API可以向我的手机发送通知。但是您要记录它是好的。我喜欢被手机弄成这样的东西!
Simon_Weaver

0

以上工作有几个答案。我想要一种不必不断更改代码且不会使我的代码不安全的方法。因此,我创建了一个白名单。白名单可以在任何数据存储中维护。我使用配置文件,因为它是一个很小的列表。

我的代码如下。

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, error) => {
    return error == System.Net.Security.SslPolicyErrors.None || certificateWhitelist.Contains(cert.GetCertHashString());
};

0

此解决方案的Unity C#版本:

void Awake()
{
    System.Net.ServicePointManager.ServerCertificateValidationCallback += ValidateCertification;
}

void OnDestroy()
{
    ServerCertificateValidationCallback = null;
}

public static bool ValidateCertification(object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
    return true;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.