要求 已經中止: 無法建立 SSL TLS 的安全通道 HttpWebRequest

2018-07-08

HttpWebRequest GetResponse()出現"要求已經中止: 無法建立 SSL/TLS 的安全通道"錯誤

  • 25121
  • 0
  • 工作雜記
  • 2021-07-20

之前因為工作需求寫了一隻小程式,每天在固定時間連線到台銀抓取當日收盤匯率

今天心血來潮去看看這隻程式是否安好時,發現從7月開始的匯率都沒抓到

打開程式的log,看到一整排的「要求已經中止: 無法建立 SSL/TLS 的安全通道」

連回台銀的匯率網站,發現台銀已經改用https了

之前因為工作需求寫了一隻小程式,每天在固定時間連線到台銀抓取當日收盤匯率

今天心血來潮去看看這隻程式是否安好時,發現從7月開始的匯率都沒抓到

打開程式的log,看到一整排的「要求已經中止: 無法建立 SSL/TLS 的安全通道」

連回台銀的匯率網站,發現台銀已經改用https了

拿這個錯誤訊息直接餵狗,得到的解法幾乎都是加上一段

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

但我加上後卻還是出現一樣的錯誤訊息

後來看到卡卡米寫的文章

在呼叫GetResponse()前加上這段程式,指定使用TLS 1.2,程式就能正常運作了

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

朝著這個方向去尋找原因,發現程式預設使用的是SSL 3.0及TLS 1.0

在黑大的這篇文章中有提到

.NET 客戶端使用 WebClient、WCF 以 HTTPS 連線遠端主機,也會涉及 TLS 1.0/1.1/1.2 版本議題,不同版本 .NET 的處理方式不同: 
.NET 4.6 內建支援且預設使用 TLS 1.2 
.NET 4.5 內建支援,但需透過 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 設為預設協定
.NET 4 本身不支援,但安裝 .NET 4.5 後即可使用 TLS 1.2,指定 TLS 1.2 的寫法為 ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; 
(註:若不想修改 .NET 4/4.5 程式,也可透過 Registry 修改預設安全協定) 
.NET 3.5 需安裝 Hotfix 才能支援 
    KB3154518 – Reliability Rollup HR-1605 – NDP 2.0 SP2 – Win7 SP1/Win 2008 R2 SP1 
    KB3154519 – Reliability Rollup HR-1605 – NDP 2.0 SP2 – Win8 RTM/Win 2012 RTM 
    KB3154520 – Reliability Rollup HR-1605 – NDP 2.0 SP2 – Win8.1RTM/Win 2012 R2 RTM 
    KB3156421 -1605 HotFix Rollup through Windows Update for Windows 10.

而我程式使用的.NET版本為4.5.2,因此需要另外指定使用TLS 1.2

參考文章:
卡卡米的記憶體 - Google在 SSL 3.0 中發現設計缺陷
黑暗執行緒 - Windows 停用 TLS 1.0 之配套作業整理

在网上查了很多资料,基本是这么一个思路:
在通过 HttpWebRequest req
= (HttpWebRequest)HttpWebRequest.Create(url); req.Method = "GET"; HttpWebResponse sp = (HttpWebResponse)req.GetResponse(); 作处理时,有些输入有些URL会在 HttpWebResponse sp = (HttpWebResponse)req.GetResponse(); 的时候抛出一个“基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系”的异常。 最简单的办法是:
1,先加入命名空间: using System.Net.Security; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates;
2,再重载CheckValidationResult方法,返回true public bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; }
3,然后在HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url); 前面加上如下几行代码: System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; ServicePointManager.ServerCertificatidationCallback = new System.Net.Security.RemoteCertificatidationCallback(CheckValidationResult);//验证服务器证书回调自动验证

此时我发现问题可以解决,但是有一个问题是这种方法在在 .net 4.5以上是没问题的,因为如下:

v4.0

#region 程序集 System.dll, v4.0.0.0
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll
#endregion

using System;

namespace System.Net
{
    // 摘要: 
    //     指定 Schannel 安全包支持的安全协议。
    [Flags]
    public enum SecurityProtocolType
    {
        // 摘要: 
        //     指定安全套接字层 (SSL) 3.0 安全协议。
        Ssl3 = 48,
        //
        // 摘要: 
        //     指定传输层安全 (TLS) 1.0 安全协议。
        Tls = 192,
    }
}

v4.5

#region 程序集 System.dll, v4.0.0.0
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.dll
#endregion

using System;

namespace System.Net
{
    // 摘要: 
    //     指定 Schannel 安全包支持的安全协议。
    [Flags]
    public enum SecurityProtocolType
    {
        // 摘要: 
        //     指定安全套接字层 (SSL) 3.0 安全协议。
        Ssl3 = 48,
        //
        // 摘要: 
        //     指定传输层安全 (TLS) 1.0 安全协议。
        Tls = 192,
        //
        Tls11 = 768,
        //
        Tls12 = 3072,
    }
}

假如在.net 4.0上使用如下代码时一样报错

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;

此时我想在.net 4.0或者以下版本使用上面的方法就不可行,那么怎么办?

System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072;
ServicePointManager.ServerCertificatidationCallback = new System.Net.Security.RemoteCertificatidationCallback(CheckValidationResult);//验证服务器证书回调自动验证

虽然.net 4.0 SecurityProtocolType 枚举中没有 Tls11 和Tls12 两种类型那么我们只能强转!!!!!