Invoke-WebRequest 对于 HTTPS 总是失败。根据验证程序,远程证书无效

Invoke-WebRequest Always Fails For HTTPS. The remote certificate is invalid according to the validation procedure

我正在尝试在 pwsh(在 Linux)中使用 Invoke-WebRequest,但总是失败。这是一个例子:

    Invoke-WebRequest https://www.google.com

site/URL 没关系,如果它使用 HTTPS 我会得到错误。在 Windows 机器上运行完全相同的脚本没有问题。

$PSVersionTable

> Name                           Value
> ----                           -----
> PSVersion                      7.0.0
> PSEdition                      Core
> GitCommitId                    7.0.0
> OS                             Linux 3.10.0-514.21.1.el7.x86_64 #1 SMP Thu May 25 17:04:51 UTC 2017
> Platform                       Unix
> PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
> PSRemotingProtocolVersion      2.3
> SerializationVersion           1.1.0.1
> WSManStackVersion              3.0

dotnet --version

3.1.403

openssl版本

OpenSSL 1.0.1e-fips 11 Feb 2013

我知道可以在 Invoke-WebRequest 方法上禁用 SSL 验证,但我真的宁愿避免它,而且,我在执行 dotnet restore[=30 之类的操作时也遇到了同样的问题=]

如果我使用 curl https://www.google.com,它似乎工作正常。我的理解是 pwsh 使用 dotnet 来实际发出这个 webrequest,而 dotnet 使用 openssl 作为 https...这可能都是错误的,但我一直在尝试使用 openssl 进行调试。

当我执行 openssl s_client -connect www.google.com:443 时,似乎表明一切正常。我可以看到证书链:

> Certificate chain  
>  0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com    
>    i:/C=US/O=Google Trust Services/CN=GTS CA 1O1
>  1 s:/C=US/O=Google Trust Services/CN=GTS CA 1O1    
>    i:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign

和0的return代码(ok)

Start Time: 1612285043
Timeout   : 300 (sec)
Verify return code: 0 (ok)

如果我在 .ps1 脚本中捕获到异常,我可以看到更多信息:

The remote certificate is invalid according to the validation procedure.
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslStream.ThrowIfExceptional()
   at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetResponse(HttpClient client, HttpRequestMessage request, Boolean keepAuthorization)
   at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()

但我仍然不知道下一步该去哪里。

最后 - 虽然我无法确定发生了什么变化,但我知道这个曾经在这台机器上工作。我很想将所有内容都升级到最新版本,但是当它与我现在拥有的版本一起使用时,很难证明这种更改是合理的。

谁能帮我指明正确的方向?

编辑

附加信息 - 当我 运行 curl -verbose https://www.google.com 我看到正在使用哪个证书:

* Connected to www.google.com (74.125.195.105) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

我没有看到 openssl 的 s_client 的等效项,但是 运行ning strace -e open openssl s_client -connect www.google.com:443 | & grep open 显示:

open("/etc/pki/tls/openssl.cnf", O_RDONLY) = 3
open("/etc/pki/tls/cert.pem", O_RDONLY) = 3

但我没能看到 pwsh 试图访问我安装的任何根 ca。当我在线搜索时,我只看到很多人说 Linux 上的 dotnet 核心使用 OpenSSL,我应该查看 openssl.cnf 文件 - 但是当我从命令行使用 openssl 时,似乎上班?!?

再次 - 任何帮助将不胜感激。似乎 pwsh 没有使用我拥有的证书?

由于您要求的是指导而不是解决方案:几乎可以肯定的是,powershell 不知道在哪里可以找到要信任的证书颁发机构的信任库。弄清楚如何告诉它信任库在哪里,或者弄清楚如何用特定证书告诉 invoke-webrequest 是我要开始的地方。