在 PowerShell 中使用 System.Net.WebClient 访问带有 SAN 证书的 HTTPS URL

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14710449/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 16:52:21  来源:igfitidea点击:

Using System.Net.WebClient in PowerShell to access a HTTPS URL with SAN Certificate

.netpowershellwebclientpowershell-2.0powershell-3.0

提问by Robin

Bit of an odd problem here. The script we're using is:

这里有点奇怪的问题。我们使用的脚本是:

$username = "itrpo"
$url = "https://homepages.domain.com/cgi-bin/checkperms.cgi?user=$username"
$homepagesUser = "REMOVED"
$homepagesPass = "REMOVED"
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = new-object System.Net.NetworkCredential($homepagesUser, $homepagesPass)
$result = $webclient.DownloadString($url)

When running this from my desktop (Windows 8, PowerShell v3 using .NET v4.0.30319) it works. When running this from a server (Windows Server 2008 R2, PowerShell v2 using .NET v2.0.50727) it does not. Ultimately it hangs and returns the error: Exception calling "DownloadString" with "1" argument(s): "The operation has timed out"

从我的桌面(Windows 8,使用 .NET v4.0.30319 的 PowerShell v3)运行它时,它可以工作。当从服务器(Windows Server 2008 R2、PowerShell v2 使用 .NET v2.0.50727)运行它时,它不会。最终它挂起并返回错误:使用“1”参数调用“DownloadString”的异常:“操作已超时”

Using NetMon I managed to determine that on the server it was failing to perform any TLS client key exchange.

使用 NetMon 我设法确定在服务器上它无法执行任何 TLS 客户端密钥交换。

The SSL certificate for homepages.domain.com is actually a SAN certificate, with homepages being an alias for the actual server name (let's call it servera.domain.com). When I changed $url in the script to use the actual server name as so:

homepages.domain.com 的 SSL 证书实际上是一个 SAN 证书,主页是实际服务器名称的别名(我们称之为 servera.domain.com)。当我在脚本中更改 $url 以使用实际服务器名称时:

$url = "https://servera.domain.com/cgi-bin/checkperms.cgi?user=$username"

... it worked, but this is not ideal (if the service is moved to another machine the script will break).

...它起作用了,但这并不理想(如果将服务移到另一台机器上,脚本将中断)。

It seems as though PowerShell v2 (.NET v2) is having problems with the SAN certificate? Further evidence to support this is that we use the above style script against another server with a standard SSL certificate it communicates fine.

似乎 PowerShell v2 (.NET v2) 的 SAN 证书有问题?支持这一点的进一步证据是,我们将上述样式脚本用于另一台具有标准 SSL 证书的服务器,它可以正常通信。

Could it be due to differences in the WebClient class being used? Here is the documentation for it under .NET v2: http://msdn.microsoft.com/en-us/library/system.net.webclient%28v=vs.80%29.aspxand the documentation for it under .NET v4: http://msdn.microsoft.com/en-us/library/system.net.webclient%28v=vs.100%29.aspx

可能是由于使用的 WebClient 类存在差异吗?这是 .NET v2 下的文档:http: //msdn.microsoft.com/en-us/library/system.net.webclient%28v=vs.80%29.aspx和 .NET 下的文档v4:http: //msdn.microsoft.com/en-us/library/system.net.webclient%28v=vs.100%29.aspx

I don't know enough about programming to really interpret the above documentation properly (or know if I'm on the right track).

我对编程知之甚少,无法真正正确地解释上述文档(或者知道我是否在正确的轨道上)。

Ideally we want that script to function under PowerShell v2 and .NET v2 without having to upgrade things or force PowerShell to use .NET v4. If my suspicion is correct is there is parameter we can specify / a way to modify the script to "fix" this issue?

理想情况下,我们希望该脚本能够在 PowerShell v2 和 .NET v2 下运行,而无需升级或强制 PowerShell 使用 .NET v4。如果我的怀疑是正确的,是否有参数我们可以指定/修改脚本以“修复”此问题的方法?

Many thanks for any advice.

非常感谢您的任何建议。

回答by Goyuix

My hunch is that this is less related to the PowerShell version (or underlying platform details in general) and more related to the certificate and the HTTPS handshake. It could be there have been improvements in recognizing alternate subject names embedded in a certificate, but an easy way to test it would be to add this line of PowerShell into your script:

我的预感是这与 PowerShell 版本(或一般的底层平台详细信息)关系不大,而与证书和 HTTPS 握手更相关。在识别嵌入在证书中的替代主题名称方面可能有所改进,但测试它的一种简单方法是将这行 PowerShell 添加到您的脚本中:

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

This will cause all certificates to be accepted - regardless if they are trusted or not, expired, etc. This is a big hammer and it wouldn't be wise to use it in production setting, but it could be useful in helping to diagnose what it going on in your setup.

这将导致所有证书都被接受 - 无论它们是否受信任、过期等。这是一个大锤子,在生产环境中使用它是不明智的,但它可能有助于诊断什么它在您的设置中进行。

You can see more information on the ServerCertificateValidationCallbackon the MSDN page including the parameters it passes into the delegate. You could in theory just whitelist the certificate you are using on that one server and return true for that one.

您可以在 MSDN 页面上查看有关ServerCertificateValidationCallback 的更多信息,包括它传递给委托的参数。理论上,您可以将您在该服务器上使用的证书列入白名单,并为该服务器返回 true。