从今年2月份开始,Github移除了一些弱的加密算法(参考GitHub Engineering - Weak cryptographic standards removal notice),导致的一个结果是,现在通过HTTPS访问Github,必须要有TLS1.2的支持。那PowerShell如何支持TLS1.2呢,请继续阅读。
微软从DotNet Framework 4.5才开始支持TLS1.2,Windows 7上默认的Powershell是2.0版本,能使用的DotNet Framework版本最高只到4.0,所以是不支持TLS1.2的。
如果使用Powershell去访问GitHub的Api,例如https://api.github.com/repos/PowerShell/PowerShell/releases/latest
,会出现具体原因不详的连接被关闭的错误。示例代码如下:
(New-Object Net.WebClient).DownloadString('https://api.github.com/repos/PowerShell/PowerShell/releases/latest')
会出现以下错误:
Exception calling "DownloadString" with "1" argument(s): "The underlying connec
tion was closed: An unexpected error occurred on a send."
At line:1 char:49
+ (New-Object Net.WebClient).DownloadString('https://api.github.com/rep ...
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
为了解决这个问题,首先要将Powershell升级。通过Chocolatey,你可以通过以下命令把Powershell升级到5.1:
choco install powershell
需要在有管理员权限的Cmd里面运行上面的命令才可以,安装完之后需要重启电脑。
在升级后的PowerShell中运行:
(New-Object Net.WebClient).DownloadString('https://api.github.com/repos/PowerShell/PowerShell/releases/latest')
会有这样的错误提示:
Exception calling "DownloadString" with "1" argument(s): "The request was aborted: Could not create SSL/TLS secure channel."
At line:1 char:1
+ (New-Object Net.WebClient).DownloadString('https://api.github.com/rep ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
检查一下[Net.ServicePointManager]::SecurityProtocol,发现TLS1.2并不在其中,只有SSL3和TLS:
> [Net.ServicePointManager]::SecurityProtocol
Ssl3, Tls
查看[Net.SecurityProtocolType]::Tls12
,可以发现TLS1.2是被当前的DotNet支持的,于是可以通过以下代码添加对TLS1.2的支持:
[Net.ServicePointManager]::SecurityProtocol =
[Net.SecurityProtocolType]::Tls12 -bor `
[Net.SecurityProtocolType]::Tls11 -bor `
[Net.SecurityProtocolType]::Tls -bor `
[Net.SecurityProtocolType]::Ssl3
上面的代码可以简写成:
[Net.ServicePointManager]::SecurityProtocol = "Tls12, Tls11, Tls, Ssl3"
或者
[System.Net.ServicePointManager]::SecurityProtocol = @("Tls12","Tls11","Tls","Ssl3")
于是再次运行:
(New-Object Net.WebClient).DownloadString('https://api.github.com/repos/PowerShell/PowerShell/releases/latest')
发现出了一个新的错误:
Exception calling "DownloadString" with "1" argument(s): "The server committed a protocol violation.
Section=ResponseStatusLine"
At line:1 char:1
+ (New-Object Net.WebClient).DownloadString('https://api.github.com/rep ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
通过一番调查,发现GitHub的服务器对HTTP请求的字段有要求,必须得有user-agent
字段,所以调整一下代码:
$wc = New-Object System.Net.WebClient
$wc.Headers.Add("user-agent", "anything")
$wc.DownloadString('https://api.github.com/repos/PowerShell/PowerShell/releases/latest')
调用成功,获得了正常的HTTP响应。
后记
- 其实可以不用使用System.Net.WebClient,而直接使用高版本的PowerShell中带的Invoke-WebRequest这个Cmdlet来读取GitHub Api。这样的话就不需要设置
user-agent
字段了。
参考:
- StackOverflow: Invoke-WebRequest SSL fails?
- StackOverflow:Powershell Invoke-WebRequest Fails with SSL/TLS Secure Channel
- StackOverflow: Webclient.DownloadFile() .aspx file won’t open
- StackOverflow: C# HttpWebRequest The underlying connection was closed: An unexpected error occurred on a send
- StackOverflow: Powershell v3 Invoke-WebRequest HTTPS error
- StackOverflow: Does WebClient use KeepAlive?
- StackOverflow:The server committed a protocol violation. Section=ResponseStatusLine ERROR
- Ignoring SSL Trust in PowerShell using System.Net.WebClient
- Download latest GitHub release via Powershell
- 3 ways to download files with PowerShell
(完)