Net.HttpWebRequest 在 PowerShell 7 中没有证书
Net.HttpWebRequest has no certificates in PowerShell7
此代码适用于 PS5,但不适用于 PS7。
它不会抛出任何错误,它只是不显示证书
$url = "https://mcr.microsoft.com/v2/azure-app-service/samples/aspnethelloworld/manifests/latest"
$req = [Net.HttpWebRequest]::Create($url)
$req.GetResponse() | Out-Null
$req.ServicePoint.Certificate | Format-List
PS5 输出:
> $req.ServicePoint
BindIPEndPointDelegate :
ConnectionLeaseTimeout : -1
Address : https://mcr.microsoft.com/v2/azure-app-service/samples/aspnethelloworld/manifests/latest
MaxIdleTime : 100000
UseNagleAlgorithm : True
ReceiveBufferSize : -1
Expect100Continue : True
IdleSince : 1/7/2022 10:30:21 AM
ProtocolVersion : 1.1
ConnectionName : https
ConnectionLimit : 2
CurrentConnections : 2
Certificate : System.Security.Cryptography.X509Certificates.X509Certificate
ClientCertificate :
SupportsPipelining : True
> $req.ServicePoint.Certificate | Format-List
Handle : 2520270205792
Issuer : CN=Microsoft Azure TLS Issuing CA 05, O=Microsoft Corporation, C=US
Subject : CN=mcr.microsoft.com, O=Microsoft Corporation, L=Redmond, S=WA, C=US
PS7 输出:
> $req.ServicePoint
BindIPEndPointDelegate :
ConnectionLeaseTimeout : -1
Address : https://mcr.microsoft.com/v2/azure-app-service/samples/aspnethelloworld/manifests/latest
MaxIdleTime : 100000
UseNagleAlgorithm : True
ReceiveBufferSize : -1
Expect100Continue : True
IdleSince : 07/01/2022 10:27:17
ProtocolVersion : 1.1
ConnectionName : https
ConnectionLimit : 2
CurrentConnections : 0
Certificate :
ClientCertificate :
SupportsPipelining : True
为什么 PowerShell 7 不返回 [Net.HttpWebRequest]
中的证书。还有其他选择吗?
HttpWebRequest
API 表面尚未完全移植到较新版本的 .NET/Core,详见 this Github issue:
HttpWebRequest
is API which is obsolete - see https://github.com/dotnet/platform-compat/blob/master/docs/DE0003.md.
We ported only the most important parts of it to .NET Core.
The recommended Networking API is HttpClient
.
要使用 HttpClient
检查远程证书,您需要利用证书验证回调 - 在 PowerShell 7 中,它看起来像这样:
$url = "https://mcr.microsoft.com/v2/azure-app-service/samples/aspnethelloworld/manifests/latest"
# Create a (thread-safe) hashtable to hold any certificates discovered
$certTable = [hashtable]::Synchronized(@{})
# Create a handler
$handler = [System.Net.Http.HttpClientHandler]::new()
# Attach a custom validation callback that saves the remote certificate to the hashtable
$handler.ServerCertificateCustomValidationCallback = {
param(
[System.Net.Http.HttpRequestMessage]$Msg,
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Cert,
[System.Security.Cryptography.X509Certificates.X509Chain]$Chain,
[System.Net.Security.SslPolicyErrors]$SslErrors
)
# Save the certificate
$certTable[$Msg.RequestUri] = $Cert
# Leave actual policy validation as-is
return [System.Net.Security.SslPolicyErrors]::None -eq $SslErrors
}.GetNewClosure()
# Create a new http client with our custom handler attached
$client = [System.Net.Http.HttpClient]::new($handler)
# Prepare request message
$request = [System.Net.Http.HttpRequestMessage]::new([System.Net.Http.HttpMethod]::Get, $url)
# Send request
$response = $client.Send($request)
# callback routine will now have populated the table with the certificate
$certTable[$request.RequestUri]
此代码适用于 PS5,但不适用于 PS7。 它不会抛出任何错误,它只是不显示证书
$url = "https://mcr.microsoft.com/v2/azure-app-service/samples/aspnethelloworld/manifests/latest"
$req = [Net.HttpWebRequest]::Create($url)
$req.GetResponse() | Out-Null
$req.ServicePoint.Certificate | Format-List
PS5 输出:
> $req.ServicePoint
BindIPEndPointDelegate :
ConnectionLeaseTimeout : -1
Address : https://mcr.microsoft.com/v2/azure-app-service/samples/aspnethelloworld/manifests/latest
MaxIdleTime : 100000
UseNagleAlgorithm : True
ReceiveBufferSize : -1
Expect100Continue : True
IdleSince : 1/7/2022 10:30:21 AM
ProtocolVersion : 1.1
ConnectionName : https
ConnectionLimit : 2
CurrentConnections : 2
Certificate : System.Security.Cryptography.X509Certificates.X509Certificate
ClientCertificate :
SupportsPipelining : True
> $req.ServicePoint.Certificate | Format-List
Handle : 2520270205792
Issuer : CN=Microsoft Azure TLS Issuing CA 05, O=Microsoft Corporation, C=US
Subject : CN=mcr.microsoft.com, O=Microsoft Corporation, L=Redmond, S=WA, C=US
PS7 输出:
> $req.ServicePoint
BindIPEndPointDelegate :
ConnectionLeaseTimeout : -1
Address : https://mcr.microsoft.com/v2/azure-app-service/samples/aspnethelloworld/manifests/latest
MaxIdleTime : 100000
UseNagleAlgorithm : True
ReceiveBufferSize : -1
Expect100Continue : True
IdleSince : 07/01/2022 10:27:17
ProtocolVersion : 1.1
ConnectionName : https
ConnectionLimit : 2
CurrentConnections : 0
Certificate :
ClientCertificate :
SupportsPipelining : True
为什么 PowerShell 7 不返回 [Net.HttpWebRequest]
中的证书。还有其他选择吗?
HttpWebRequest
API 表面尚未完全移植到较新版本的 .NET/Core,详见 this Github issue:
HttpWebRequest
is API which is obsolete - see https://github.com/dotnet/platform-compat/blob/master/docs/DE0003.md.
We ported only the most important parts of it to .NET Core. The recommended Networking API isHttpClient
.
要使用 HttpClient
检查远程证书,您需要利用证书验证回调 - 在 PowerShell 7 中,它看起来像这样:
$url = "https://mcr.microsoft.com/v2/azure-app-service/samples/aspnethelloworld/manifests/latest"
# Create a (thread-safe) hashtable to hold any certificates discovered
$certTable = [hashtable]::Synchronized(@{})
# Create a handler
$handler = [System.Net.Http.HttpClientHandler]::new()
# Attach a custom validation callback that saves the remote certificate to the hashtable
$handler.ServerCertificateCustomValidationCallback = {
param(
[System.Net.Http.HttpRequestMessage]$Msg,
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Cert,
[System.Security.Cryptography.X509Certificates.X509Chain]$Chain,
[System.Net.Security.SslPolicyErrors]$SslErrors
)
# Save the certificate
$certTable[$Msg.RequestUri] = $Cert
# Leave actual policy validation as-is
return [System.Net.Security.SslPolicyErrors]::None -eq $SslErrors
}.GetNewClosure()
# Create a new http client with our custom handler attached
$client = [System.Net.Http.HttpClient]::new($handler)
# Prepare request message
$request = [System.Net.Http.HttpRequestMessage]::new([System.Net.Http.HttpMethod]::Get, $url)
# Send request
$response = $client.Send($request)
# callback routine will now have populated the table with the certificate
$certTable[$request.RequestUri]