it-swarm.com.de

Powershell Invoke-RestMethod über HTTPS

Ich versuche mit einem Dienst über Powershell zu kommunizieren, scheitere aber kläglich. Ich vermute, es ist das Zertifikat und ich habe nach der Antwort gegoogelt und zwei Optionen gefunden, von denen keine für mich funktioniert hat. Ich habe auch versucht, die beiden erfolglos zu kombinieren.

Option 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"

Option 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"

Hier ist die Fehlermeldung:

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

Ich möchte hinzufügen:

  • das direkte Surfen zum Dienst funktioniert mit einem Webbrowser
  • Ich habe versucht, mich auch für HTTP zu öffnen, und das hat funktioniert
  • Das vom Dienst verwendete Zertifikat ist selbstsigniert, wird jedoch von meinem Computer über ein Stammzertifikat als vertrauenswürdig eingestuft (in IE oder Chrome treten keine Warnungen auf).
  • Ich habe Netzwerk-Captures durchgeführt und sichergestellt, dass ein Paket tatsächlich den Server erreicht.

Anregungen geschätzt!

Herzliche Grüße, Patrik

Aktualisierter Beitrag zu Vorschlägen von Mr Tree:

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              :

Update 2 basierend auf einem Kommentar von Mr Tree:

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
13
PatrikJ

Ich löste das Rätsel, während ich eine andere Sache ausfindig machte. Der betreffende Webserver unterstützte nur TLS1.1 und TLS1.2. Powershell scheint das NICHT zu unterstützen. Wenn ich TLS1.0 aktiviert habe, hat es funktioniert. 

Um TLS1.2 zu erzwingen, können Sie diese Zeile verwenden:

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

Hoffe das hilft jemand anderem und vielen Dank für alle hilfreichen Kommentare!

/ Patrik

34
PatrikJ

Ich habe in letzter Zeit viele Schmerzen durchgemacht, um eine ähnliche Situation zu überwinden. Ich habe einen Proof-of-Concept erstellt und dabei einen Test-Service SaaS verwendet. Der Dienst besaß ein selbstsigniertes SSL-Zertifikat. Daher wollte ich Zertifikatfehler ignorieren, während ich versuchte, eine POST -Methode aufzurufen (ähnlich dem Parameter "-k" für curl). Nach langem Kampf fand ich heraus, dass beide - (a) der Aufruf zum Ignorieren von Fehlern bei der Zertifizierungsprüfung und (b) eine explizite Einstellung für TLS 1.2 als Sicherheitsprotokoll erforderlich waren. Ich denke letzteres, weil der Dienst die Verbindungsversuche mit einem der anderen Protokolle möglicherweise abgelehnt hat. (Ich habe zu viel Zeit damit verbracht, die verschiedenen Variationen zu testen, um sie wie in verschiedenen SOF-Threads vorgeschlagen zu machen, aber unabhängig voneinander ...)

Hier ist der Code, der funktioniert hat ... 

Important: Der Bypass der Zertifizierungsprüfung bezieht sich ausschließlich auf den Prototyp/PoC. Wir haben nicht vor, dies in der Produktion zu tun (und das sollten Sie auch nicht!). 

$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
}

Ich möchte auch hinzufügen, dass sich die bevorzugten Sicherheitsprotokolle ständig ändern, da verschiedene Schwachstellen entdeckt und Korrekturen implementiert werden. Darüber hinaus haben verschiedene Systeme (SSL/TLS-Stacks in Client-Betriebssystemen und Servern/Diensten) oftmals ihre eigenen Möglichkeiten, um die neuesten/sichersten Optionen zu nutzen. Welches Flag möglicherweise funktioniert, hängt also von den Client- und Server-Systemen und auch von der Zeit ab (TLS1.2 bleibt einige Monate später möglicherweise nicht bevorzugt). Idealerweise sollte man überhaupt keine Flagge angeben müssen. Weitere Informationen finden Sie im Abschnitt "Hinweise" in diesem MSDN-Dokument .

0
mprabhu11

Es scheint, dass Sie versuchen, eine Json-API mit Invoke-RestMethod aufzurufen. Nach der Dokumentation :

-Inhaltstyp

Gibt den Inhaltstyp der Webanfrage an.

Wenn dieser Parameter nicht angegeben wird und die request-Methode POST ist, Invoke-RestMethod setzt den Inhaltstyp auf "application/x-www-form-urlencoded". Andernfalls lautet der Inhaltstyp nicht im Anruf angegeben.

Um einen Json-Body zu verwenden, müssen Sie Invoke-RestMethod -ContentType 'application/json' <other args> verwenden.

0
Eris