访问不同站点时出现不一致的SSL错误

问题描述

这不是“为什么我的代码不通过HTTPS下载”的问题之一。几年前,我已经阅读并阅读了所有这些文章,从那以后,我成功地多次实施了这种方法

我的非常简单的针对4.7.1框架并在4.7.2框架上运行的C#代码尝试通过HTTPS下载资源。它遵循有关配置ServicePointManagerWebClientWebRequest的所有常见建议。最初,我在局域网上使用Apache 2.4.20实例对其进行了测试,并且工作正常。接下来,我在公共Internet上与其他几个服务器一起对其进行了测试,即使在瞬间在浏览器中打开页面,我也遇到了在发出请求后约5秒钟内发生的错误

{"The request was aborted: Could not create SSL/TLS secure channel."}

我检查了服务器证书。它们受到Mozilla和Windows的信任,并以完全信任的模式在我已知的任何浏览器中打开。这些站点通过TLS 1.2进行响应。服务器或其证书没有明显的错误。为了进行健全性检查,我使用了Google的首页地址https://www.google.ca/?gws_rd=ssl,它的打开效果很好。有些站点打开,而其他站点则没有。我尝试一次启用一个TLS版本,每个版本在每个工作站点上均能很好地工作,而在所有非工作站点上都没有。

这是我的代码。它被编写为与基本身份验证一起使用,但也经过了测试,没有基本身份验证。这不是身份验证问题。

ServicePointManager.Expect100Continue = true;
ServicePointManager.DefaultConnectionLimit = 9999;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; // | SecurityProtocolType.Tls | SecurityProtocolType.Ssl3; // tested by enabling only 1 protocol at a time locally. Each worked.

if (ServicePointManager.ServerCertificateValidationCallback == null) // for testing only
{
    ServicePointManager.ServerCertificateValidationCallback += (se,cert,chain,sslerror) => { return true; };
}

using (var client = new WebClientEx()) // Ex adds Timeout and CookieContainer
{
    client.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
    client.Headers.Add("Cache-Control","no-cache");
    client.Encoding = Encoding.UTF8;

    var cc = new CredentialCache();
    // Using one or the other,depending on the situation,or none
    //cc.Add(url,"Basic",new NetworkCredential(user,pass));
    //cc.Add(new Uri(url.GetLeftPart(UriPartial.Authority)),"Digest",pass));
    client.Credentials = cc;

    return client.DownloadData(url);
}

在退回到WebClient之前,我尝试使用普通的HttpRequest来进行可靠的超时,这对我的实现很重要:

var req = (HttpWebRequest)WebRequest.Create(url);
req.Timeout = (int)timeout.TotalMilliseconds;
req.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; // tried with or w/o

var encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes($"{user}:{pass}"));
req.Headers.Add("Authorization","Basic " + encoded); // tried with or w/o

var credentialCache = new CredentialCache();
credentialCache.Add(url,pass)); // tried with or w/o
req.Credentials = credentialCache;
req.PreAuthenticate = true; // tried with or w/o
using (var response = (HttpWebResponse)req.GetResponse())
{
    using (var ms = new MemoryStream())
    {
        response.GetResponseStream().copyTo(ms);
        return ms.ToArray();
    }
}

我的代码的两个变体同样适用于本地Apache和Google,但不适用于某些其他站点。我的代码找不到任何错误https://jigsaw.w3.org/HTTP/Basic/是无法正常工作的网站之一,可以在任何浏览器中正常打开。这是我们大多数软件用于单元测试的站点,因此,我有望在测试阶段以及在生产环境中使用的任何任意Web服务器上生成与之兼容的东西。

我打开了System.Net跟踪,并比较了成功和失败的下载尝试,不同之处在于一个进行握手,而另一个立即失败。跟踪中没有有用的信息。

有什么主意吗?

此问题中提到的所有服务和技术都超出了我的控制范围,因此必须保留它们当前的状态。我无权更改任何版本或安装任何更新。它必须以当前的方式工作。如果您不满意,请跳过其他问题。

解决方法

答案是“代码没有任何问题”。我必须测试的那些选择服务器实际上出了点问题。它们过时或利基,并且在某种程度上不符合.NET Framework拒绝与它们进行互操作的程度。在我使用兼容的现代服务器进行测试后,无论是通过HTTP还是HTTPS以及基本身份验证或摘要身份验证,一切都按预期工作。