如何在不使用证书的情况下,使用C# 2.0 WebClient忽略证书错误

43
使用Visual Studio 2005 - C# 2.0,System.Net.WebClient.UploadData(Uri address, byte[] data),Windows Server 2003。
以下是代码的简化版本:
static string SO_method(String fullRequestString)
{
    string theUriStringToUse = @"https://10.10.10.10:443"; // populated with real endpoint IP:port
    string proxyAddressAndPort = @"http://10.10.10.10:80/"; // populated with a real proxy IP:port
    Byte[] utf8EncodedResponse; // for the return data in utf8
    string responseString; // for the return data in utf16

    WebClient myWebClient = new WebClient(); // instantiate a web client
    WebProxy proxyObject = new WebProxy(proxyAddressAndPort, true);// instantiate & popuylate a web proxy
    myWebClient.Proxy = proxyObject; // add the proxy to the client
    myWebClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); // stick some stuff in the header

    UTF8Encoding utf8Encoding = new UTF8Encoding(false);// create a utf8 encoding
    Byte[] utf8EncodedRequest = HttpUtility.UrlEncodeToBytes(fullRequestString, utf8Encoding); // convert the request data to a utf8 byte array

    try
    {
        utf8EncodedResponse = myWebClient.UploadData(theUriStringToUse, "POST", utf8EncodedRequest); // pass the utf8-encoded byte array
        responseString = utf8Encoding.GetString(utf8EncodedResponse); // get a useable string out of the response
    }
    catch (Exception e)
    {
        // some other error handling
        responseString = "<CommError><![CDATA[" + e.ToString() + "]]></CommError>";// show the basics of the problem
    }
    return responseString;// return whatever ya got
}

这是我收到的错误信息:
底层连接已关闭:无法为 SSL/TLS 安全通道建立信任关系。
当请求发出时,我没有太多控制权来查看发生了什么。有人告诉我它已经到达了正确的目的地,但出现了“证书错误”。这据说是因为我的请求中的 IP 地址与解析出的 URL 不匹配。我有多个 IP 地址需要轮询,所以指定 URL 表示不可行。我没有附加证书,也不应该根据终端点所有者的说法。按照“他们”的说法,证书错误是“正常的”,我应该忽略它。
问题中涉及的证书据说是我们服务器上的许多 Verisign 证书之一。我看了一下 .net WebService, bypass ssl validation!,它有点描述了我的问题,但也有点不一样,因为我不知道应该引用哪个证书(如果有)。
有没有办法让我忽略错误,而不必真正知道/关心哪个证书导致了问题?
请小心操作,使用简单易懂的语言和“白痴式”的代码,因为我并不是一个专业人士。
这个流量是通过专用线路传输的,所以我理解忽略证书错误不像在公开互联网上那么重要。
6个回答

63

SSL证书是用于建立机器之间的信任关系。如果您输入了一个IP地址,却最终与另一个IP地址通信,那么这听起来就像是DNS劫持安全漏洞,而SSL旨在帮助您避免这种情况-也许这是您不想从“他们”那里承受的某些事情。

如果您可能会与多个机器通信(理想情况下,它们会为您呈现为一个机器),则您需要为每台可能的机器获取一个证书以启动信任。

要忽略信任(我只在开发场景中临时使用过此选项),以下代码段可能适用于您,但我强烈建议您在使用之前考虑忽略信任的影响:

public static void InitiateSSLTrust()
{
    try
    {
        //Change SSL checks so that all checks pass
        ServicePointManager.ServerCertificateValidationCallback =
           new RemoteCertificateValidationCallback(
                delegate
                { return true; }
            );
    }
    catch (Exception ex)
    {
        ActivityLog.InsertSyncActivity(ex);
    }
}

1
谢谢,MattH。在调用System.Net.WebClient.UploadData(Uri address, byte[] data)方法之前,我正在执行TRY块中的代码。说我不确定它正在做什么是低估了。我没有看到与我的WebClient的关联。然而,“似乎”它正在工作,因为我们在我的一侧的网络团队中似乎在沟通方面取得了进展。我在MSDN上找到了一个非常相似的建议,但文字似乎只是在我的眼珠上弹来弹去。http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager%28VS.80%29.aspx - JohnTheBarber
2
简而言之,上述代码信任任何人,并绕过所有SSL验证,因此不安全。 - MattH
1
对 - 我明白这一点 - 但这是否与我的特定WebClient实例,我的运行进程或服务器上任何与证书相关的“事件”有关?我猜想它仅限于我的进程,但是... - JohnTheBarber
哦-是的-这个流量是通过专用线路传输的——刚刚在问题中添加了一个符号来表示这一点。但是我在想——我知道我们的站点到另一方没有物理专用电缆。中间所有的电线必须共享其他流量... - JohnTheBarber

24

我知道这是一篇旧文章了,但我只想展示一下有一种更加简洁的方法可以实现这个(使用.NET 3.5+及更高版本)。

也许只是我的强迫症作祟,但我希望将代码最小化。这似乎是最短的方法,但我也列出了一些较长的等价形式:

// 79 Characters (72 without spaces)
ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;

.NET 2.0中最短的方法(这正是问题所特别询问的)

// 84 Characters
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

很遗憾,lambda表达式需要您定义参数,否则它可能会更短。

如果您需要一个更长的替代方案,这里有一些额外的选择:

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

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

// 255 characters - lots of code!
ServicePointManager.ServerCertificateValidationCallback =
    new RemoteCertificateValidationCallback(
        delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true;
        });

虽然这可能有其使用情况,如果您想在主类中禁用证书验证,但您应该记住,如果在每个请求构造的类内部使用,这可能会导致潜在的内存泄漏。此外,+=将用于订阅此回调。 - Jürgen Steinblock

12

这是我们正在使用的代码(尚未完善 - 我认为我没有正确设置错误处理,但应该接近)基于 Thomas 的建议(这是 .NET 4.0 代码):

var sslFailureCallback = new RemoteCertificateValidationCallback(delegate { return true; });

try
{

    if (ignoreSslErrors)
    {
        ServicePointManager.ServerCertificateValidationCallback += sslFailureCallback;
    }

    response = webClient.UploadData(Options.Address, "POST", Encoding.ASCII.GetBytes(Options.PostData));

}
catch (Exception err)
{
    PageSource = "POST Failed:\r\n\r\n" + err;
    return PageSource;
}
finally
{
    if (ignoreSslErrors)
    {
        ServicePointManager.ServerCertificateValidationCallback -= sslFailureCallback;
    }
}

8

这段代码的作用范围比你想象的要广泛得多。它是进程级别的,可以是exe进程、此计算机上的IIS甚至是DLLHost.exe。在调用它之后,请使用finally块将事情恢复到正常状态,通过删除始终返回true的委托。


如果该进程正在运行其他正在调用的线程,则回调函数在其设置期间仍将被使用。 - oolong

4

我想要针对特定的域名禁用SSL验证,而不是全局停用它,因为可能有其他正在运行的请求不应受到影响,所以我想出了这个解决方案(请注意,uri是类内的一个变量):

        private byte[] UploadValues(string method, NameValueCollection data)
        {
            var client = new WebClient();

            try
            {
                ServicePointManager.ServerCertificateValidationCallback +=
                    ServerCertificateValidation;

                returnrclient.UploadValues(uri, method, parameters);

            }
            finally
            {
                ServicePointManager.ServerCertificateValidationCallback -=
                    ServerCertificateValidation;
            }
        }

        private bool ServerCertificateValidation(object sender,
            X509Certificate certificate, X509Chain chain,
            SslPolicyErrors sslPolicyErrors)
        {
            var request = sender as HttpWebRequest;
            if (request != null && request.Address.Host.Equals(
                this.uri.Host, StringComparison.OrdinalIgnoreCase))
                return true;
            return false;
        }

1
这里是VB.net代码,用于使WebClient忽略SSL证书。
Net.ServicePointManager.ServerCertificateValidationCallback = New Net.Security.RemoteCertificateValidationCallback(Function() True)

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