web-dev-qa-db-ja.com

HTTPS経由のPowershell Invoke-RestMethod

PowerShellを介してサービスと通信しようとしていますが、惨めに失敗しています。私はそれが証明書であることを疑っており、私は答えをグーグル検索して2つのオプションを見つけましたが、どれも私にとってはうまくいきませんでした。また、この2つを組み合わせることに失敗しました。

オプション1:

add-type @"
    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;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

$urlJSON = "https://internal.ad.local/path/api_jsonrpc.php"

#Create authentication JSON object using ConvertTo-JSON
$objAuth = (New-Object PSObject | Add-Member -PassThru NoteProperty jsonrpc '2.0' |
Add-Member -PassThru NoteProperty method 'user.authenticate' |
Add-Member -PassThru NoteProperty params @{user="user";password="password"} |
Add-Member -PassThru NoteProperty id '2') | ConvertTo-Json


Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"

オプション2:

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

$urlJSON = "https://internal.ad.local/path/api_jsonrpc.php"

#Create authentication JSON object using ConvertTo-JSON
$objAuth = (New-Object PSObject | Add-Member -PassThru NoteProperty jsonrpc '2.0' |
Add-Member -PassThru NoteProperty method 'user.authenticate' |
Add-Member -PassThru NoteProperty params @{user="user";password="password"} |
Add-Member -PassThru NoteProperty id '2') | ConvertTo-Json


Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"

エラーメッセージは次のとおりです。

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
At C:\Users\user\AppData\Local\Temp\46eaa6f7-62a0-4c10-88d1-79212d652bc9.ps1:24 char:1
+ Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

追加します:

  • サービスに直接サーフィンすることはウェブブラウザで動作します
  • 私もHTTPに開放してみました、そしてそれはうまくいきました
  • サービスによって使用される証明書は自己署名されていますが、ルート証明書を介して私のマシンによって信頼されています(警告はIEまたはChromeで問題はありません)
  • ネットワークキャプチャを実行し、パケットが実際にサーバーに到達することを確認しました。

どんな提案も歓迎します!

敬具、パトリック

以下のツリー氏の提案に関する投稿の更新:

Name                       : lambda_method
DeclaringType              :
ReflectedType              :
Module                     : RefEmit_InMemoryManifestModule
MethodHandle               :
Attributes                 : PrivateScope, Public, Static
CallingConvention          : Standard
IsSecurityCritical         : False
IsSecuritySafeCritical     : False
IsSecurityTransparent      : True
ReturnType                 : System.Boolean
ReturnParameter            :
ReturnTypeCustomAttributes : System.Reflection.Emit.DynamicMethod+RTDynamicMethod+EmptyCAHolder
MemberType                 : Method
MethodImplementationFlags  : NoInlining
IsGenericMethodDefinition  : False
ContainsGenericParameters  : False
IsGenericMethod            : False
IsPublic                   : True
IsPrivate                  : False
IsFamily                   : False
IsAssembly                 : False
IsFamilyAndAssembly        : False
IsFamilyOrAssembly         : False
IsStatic                   : True
IsFinal                    : False
IsVirtual                  : False
IsHideBySig                : False
IsAbstract                 : False
IsSpecialName              : False
IsConstructor              : False
CustomAttributes           :
MetadataToken              :

ツリー氏のコメントに基づく更新2:

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
At C:\Users\user\AppData\Local\Temp\ff47910e-fd8e-4be8-9241-99322144976a.ps1:13 char:1
+ Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
15
PatrikJ

別の問題をトラブルシューティングしながら、謎を解決しました。問題のWebサーバーはTLS1.1およびTLS1.2のみをサポートしていました。 Powershellはそれをサポートしていないようです。 TLS1.0を有効にした場合、それは機能しました。

TLS1.2を強制するには、次の行を使用できます。

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

それが他の誰かを助けることを願っています、そしてすべての役立つコメントに感謝します!

/ Patrik

41
PatrikJ

私は最近、同じような状況を乗り越えるために多くの苦痛を経験しました。トライアルSaaSサービスを使用して、概念実証を作成していました。サービスには自己署名SSL証明書があったため、POSTメソッドを呼び出そうとしたときの証明書エラーを無視したかった(curlの「-k」パラメーターと同様)。多くの苦労の後、両方a)証明書検証エラーを無視するための呼び出しと、(b)セキュリティプロトコルとしてのTLS 1.2の明示的な設定が必要であることがわかりました。サービスが他のプロトコルを使用して接続しようとする試みをおそらく拒否していたため、後者のように思います。 (さまざまなSOFスレッドで提案されているように、それぞれを実行するためにさまざまなバリエーションを試すのにあまりにも多くの時間を費やしましたが、独立しています...)

これが機能したコードです...

重要:証明書検証バイパスは、純粋にプロトタイプ/ PoCのためのものです。これを本番環境で行うつもりはありません(あなたもそうするべきではありません!)。

$defaultSecurityProtocol = $null
try
{   
    #BUGBUG, TODO: Disabling cert validation for the duration of this call...('trial' version cert is self-signed.)
    #Remove this after the PoC.
    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } 
    #Cache the previous protocol setting and explicitly require TLS 1.2 
    $defaultSecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol
    [System.Net.ServicePointManager]::SecurityProtocol = `
                [System.Net.SecurityProtocolType]::Tls12

    if (-not [String]::IsNullOrWhiteSpace($authZHeaderValue))
    {
        $response = Invoke-WebRequest `
                    -Uri $webhookUrl `
                    -Method "Post" `
                    -Body $eventJson `
                    -Header @{ $authZHeaderName = $authZHeaderValue} 
    }
    else 
    {
        $response = Invoke-WebRequest `
                    -Uri $webhookUrl `
                    -Method "Post" `
                    -Body $eventJson
    }
}
catch 
{
    $msg = $_.Exception.Message
    $status = $_.Exception.Status
    $hr = "{0:x8}" -f ($_.Exception.HResult)
    $innerException = $_.Exception.InnerException
    #Just issue a warning about being unable to send the notification...
    Write-Warning("`n`t[$status] `n`t[0x$hr] `n`t[$msg] `n`t[$innerException]")
}
finally 
{
    # Set securityProtocol and CertValidation behavior back to the previous state.
    [System.Net.ServicePointManager]::SecurityProtocol = $defaultSecurityProtocol
        [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null
}

また、さまざまな脆弱性が発見され、修正が実装されるにつれて、優先セキュリティプロトコルが変化し続けることも付け加えておきます。さらに、さまざまなシステム(クライアントOSおよびサーバー/サービスのSSL/TLSスタック)は、多くの場合、最新の/最も安全なオプションに対応するために独自の追いつきを持っています。したがって、正確にどのフラグが機能するかは、クライアントシステムとサーバーシステム、および時間の関数になります(その場合、TLS1.2は数か月後も優先されない可能性があります)。フラグを指定する必要がないのが理想的です。詳細については、---(このMSDNドキュメント の「備考」セクションを参照してください。

0
mprabhu11

Invoke-RestMethodでjson APIを呼び出そうとしているようです。 documentation によると:

-ContentType

Webリクエストのコンテンツタイプを指定します。

このパラメーターが省略され、リクエストメソッドがPOSTの場合、Invoke-RestMethodはコンテンツタイプを "application /に設定しますx-www-form-urlencoded "。それ以外の場合、コンテンツタイプは呼び出しで指定されません。

JSONボディを使用するには、Invoke-RestMethod -ContentType 'application/json' <other args>を使用する必要があります

0
Eris