带有HTTPS的WebClient.DownloadString“验证或解密失败”

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带有HTTPS的WebClient.DownloadString“验证或解密失败”相关的知识,希望对你有一定的参考价值。

我正在使用Windows 10上的Unity Engine(2017.2.0f3)创建一个游戏,我试图从网页上获取html。据我所知,Unity使用“Mono”C#编译器和运行时v2.0(根据在mono --version中运行UnityEditorDataMonoin的结果),还使用v5.0.1(根据在mono --version中运行UnityEditorDataMonoBleedingEdgein的结果)。我目前正在使用HTML Agility Pack进行解析。当试图访问HTTP安全网站时,例如dictionary.com,一切都按预期工作,但无论我做什么,我都无法访问HTTPS安全网站,例如urbandictionary.com(编辑:显然,问题是特定于此网站的,因为使用mozroots导入证书后,可以访问github.com),并始终收到异常:TlsException: The authentication or decryption has failed.我知道HTML Agility Pack不支持HTTPS,并根据this answer编写了我的代码。我已经尝试过herehere描述的解决方案,但无济于事。我试过运行mozroots,我位于PathTo/Unity/Editor/Data/MonoBleedingEdge/lib/mono/4.5/mozroots,使用--import--sync--quiet标志,但同样的异常被抛出(如果这确实有效,我对它的可移植性持怀疑态度,但也许我可以实现自己的mozroots的版本,如评论所建议的)。此外,我被告知Unity使用的Mono版本不支持TLS 1.2,这是有问题的。如果没有解决此问题的方法,是否有任何解决方法?

注意:为清晰起见删节

class MyWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
        request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
        return request;
    }
}

class GetHtml
{
    public static void Get(string url)
    {
        string documentString = new MyWebClient().DownloadString(url);
        ...
    }
}

class CallingClass
{
     public void CallingMethod()
     {
         ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
         //With or without the above line ^, the same TlsException is thrown. 
         GetHtml.Get("https://www.urbandictionary.com/define.php?term=example");
         //HTTP works properly, but HTTPS, as in this example, does not.
     }
}

日志如下:

TlsException: The authentication or decryption has failed.
Mono.Security.Protocol.Tls.RecordProtocol.ProcessAlert (AlertLevel alertLevel, AlertDescription alertDesc)
Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult)
Rethrow as IOException: The authentication or decryption has failed.
Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult)
Rethrow as WebException: Error getting response stream (Write: The authentication or decryption has failed.): SendFailure
System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult)
System.Net.HttpWebRequest.GetResponse ()
System.Net.WebClient.GetWebResponse (System.Net.WebRequest request)
System.Net.WebClient.DownloadDataCore (System.Uri address, System.Object userToken)

编辑:我已经尝试更新运行时版本。唯一的选择是在Project Settings-> Player菜单中从.Net 3.5更改为4.6,这是实验性的。代码运行时我仍然会遇到异常,但输出日志略有不同。

TlsException: The authentication or decryption has failed.
Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecord (System.IAsyncResult asyncResult) (at <eb1224ae7b184cd09343d47f8a05481b>:0)
Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord (System.IAsyncResult ar, System.Boolean ignoreEmpty) (at <eb1224ae7b184cd09343d47f8a05481b>:0)
Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker (System.IAsyncResult result) (at <eb1224ae7b184cd09343d47f8a05481b>:0)
Rethrow as IOException: The authentication or decryption has failed.
Mono.Security.Protocol.Tls.SslClientStream.EndNegotiateHandshake (System.IAsyncResult result) (at <eb1224ae7b184cd09343d47f8a05481b>:0)
Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (System.IAsyncResult asyncResult) (at <eb1224ae7b184cd09343d47f8a05481b>:0)
Rethrow as IOException: The authentication or decryption has failed.
Mono.Security.Protocol.Tls.SslStreamBase.EndRead (System.IAsyncResult asyncResult) (at <eb1224ae7b184cd09343d47f8a05481b>:0)
Mono.Net.Security.Private.LegacySslStream.EndAuthenticateAsClient (System.IAsyncResult asyncResult) (at <344dc4d3f1ad41809df78607b6121a41>:0)
Mono.Net.Security.Private.LegacySslStream.AuthenticateAsClient (System.String targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, System.Boolean checkCertificateRevocation) (at <344dc4d3f1ad41809df78607b6121a41>:0)
Mono.Net.Security.MonoTlsStream.CreateStream (System.Byte[] buffer) (at <344dc4d3f1ad41809df78607b6121a41>:0)
System.Net.WebConnection.CreateStream (System.Net.HttpWebRequest request) (at <344dc4d3f1ad41809df78607b6121a41>:0)
Rethrow as WebException: Error: SecureChannelFailure (The authentication or decryption has failed.)
System.Net.WebClient.DownloadDataInternal (System.Uri address, System.Net.WebRequest& request) (at <344dc4d3f1ad41809df78607b6121a41>:0)
System.Net.WebClient.DownloadString (System.Uri address) (at <344dc4d3f1ad41809df78607b6121a41>:0)
System.Net.WebClient.DownloadString (System.String address) (at <344dc4d3f1ad41809df78607b6121a41>:0)
答案

此问题计数由HTTP协议引起。如果服务器使用安全的HTTP(实际上是HTTPS),则当底层协议无法处理X509 Certificate时,可能会创建错误。

尝试更改此行:

HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;

至:

HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest; 
request.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

或者,或者,使用以下方法将验证回调应用于全局过滤器:

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

在代码中创建任何HttpWebRequest对象之前。

如果您想更仔细地处理证书验证,请在此处显示回调:https://msdn.microsoft.com/en-us/library/office/dd633677

这应该可以解决您的问题。

另一答案

经过一些严谨的研究后发现Unity(2017.2.0f3)目前使用的Mono版本不支持TLS 1.2,正如开发人员here所解释的那样。此外,仔细检查异常日志显示,在内部,正在使用遗留后端:Mono.Net.Security.Private.LegacySslStream而不是Mono.Net.Security.Private.SslStream。截至目前,唯一的解决方案将涉及第三方库或解决方法。

感谢@Evk指出我正确的方向。

以上是关于带有HTTPS的WebClient.DownloadString“验证或解密失败”的主要内容,如果未能解决你的问题,请参考以下文章

带有 HTTPS 重定向的 Nginx 入口控制器尾部斜杠

带有 HTTPS 的 XML 命名空间 URI?

带有 url 重写的 HTTPS 反向代理

带有 WCF 错误的 https:“找不到与方案 https 匹配的基地址”

使用带有 https 协议的 JMeter + Maven

带有 HTTP 和 HTTPS 基本 URL 的 AFHTTPRequestOperationManager