web-dev-qa-db-ja.com

Powershell Invokeからの自己署名証明書の無視-RestMethodは機能しません(再び変更されました...)

証明書の検証を無視するための標準ソリューションを使用した後、Invoke-RestMethodは次を返します。

Invoke-RestMethod : A system error occurred and has been logged.  Please try again later or contact your administrator.

今日、この失敗に気付いたので、Powershellの更新と関係があると思います。 「標準ソリューション」とは、次のことを意味します。

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

これは数か月前に機能を停止し、Powershellに追加されたC#タイプでコールバックを適切に設定しました(以下のHistoryの説明)。

これが私の環境です:

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.15063.674
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.15063.674
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

ここに少し歴史があるので、この質問は重複として閉じられるだけではありません。

歴史

Googleで検索したり、StackOverflowを検索したりすると、この質問に返信定型文がいくつか表示されます。しかし、今日、私はすべての標準ソリューションが機能しなくなっていることに気づきました。

Powershellが与える標準エラーは次のとおりです。

Invoke-RestMethod : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

あらゆる場所のフォーラムで与えられている標準的な答えは、Invoke-RestMethodを呼び出す前にこのコマンドを使用することです。

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

ただし、最新バージョンのWindows 10/2016とPowershellを使用している場合は、Invoke-RestMethodを呼び出すと次のようになります。

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.

それが起こる理由の説明は Huddled Massesブログ にあります。これは次のように要約できます。

ServerCertificateValidationCallbackをscriptblockに設定しても、非同期コールバック(タスクスレッドで発生するコールバック)では機能しません。これは、他のスレッドにスクリプトを実行するための実行スペースがないためです。

もともと、私はこのコードでその問題を解決していました:

if (-not ([System.Management.Automation.PSTypeName]"TrustAllCertsPolicy").Type)
{
    Add-Type -TypeDefinition  @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
    public bool CheckValidationResult(
        ServicePoint srvPoint, X509Certificate certificate,
        WebRequest request, int certificateProblem)
    {
        return true;
    }
}
"@
}

if ([System.Net.ServicePointManager]::CertificatePolicy.ToString() -ne "TrustAllCertsPolicy")
{
    [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}

しかし、Windows 10では正常に機能していましたが、Windows Server 2016では機能しませんでした。したがって、 Huddled Masses に基づいて、スクリプトではなくC#で証明書検証コールバックを処理するためにこれを作成しましたブロック:

function Disable-SslVerification
{
    if (-not ([System.Management.Automation.PSTypeName]"TrustEverything").Type)
    {
        Add-Type -TypeDefinition  @"
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public static class TrustEverything
{
    private static bool ValidationCallback(object sender, X509Certificate certificate, X509Chain chain,
        SslPolicyErrors sslPolicyErrors) { return true; }
    public static void SetCallback() { System.Net.ServicePointManager.ServerCertificateValidationCallback = ValidationCallback; }
    public static void UnsetCallback() { System.Net.ServicePointManager.ServerCertificateValidationCallback = null; }
}
"@
    }
    [TrustEverything]::SetCallback()
}
function Enable-SslVerification
{
    if (([System.Management.Automation.PSTypeName]"TrustEverything").Type)
    {
        [TrustEverything]::UnsetCallback()
    }
}

これは長い間非常にうまく機能しましたが、つい最近、Invoke-RestMethodを呼び出すと次のエラーが返され始めました。

Invoke-RestMethod : A system error occurred and has been logged.  Please try again later or contact your administrator.

適切な解決策は証明書を展開することだけであることを理解していますが、多くの場合、適切なPKIXを設定せずにテストしたいだけです。

6
petrsnd

私はこれを私が呼んでいるWebサービスの変更に絞り込んだと思います。ドー!

私の質問にリストしたDisable-SslVerificationおよびEnable-SslVerification関数は、今でも最善の方法であり、機能しているように見えます。

コメントでベーコンビットが言及した-SkipCertificateCheckスイッチを楽しみにしています。その後、ハッキングを停止できます。 =)

うまくいけば、この質問は、同じ問題を解決しようとしているが、An unexpected error occurred on a send問題に遭遇した人々にとって価値があります。

3
petrsnd