Błąd HTTPS programu PowerShell v3 Invoke-WebRequest

126

Korzystając z Invoke-WebRequest i Invoke-RestMethod programu PowerShell v3, z powodzeniem użyłem metody POST do wysłania pliku json do witryny https.

Polecenie, którego używam, to

 $cert=New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("cert.crt")
 Invoke-WebRequest -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert -Body $json -ContentType application/json -Method POST

Jednak gdy próbuję użyć metody GET, takiej jak:

 Invoke-WebRequest -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert -Method GET

Zwracany jest następujący błąd

 Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
 At line:8 char:11
 + $output = Invoke-RestMethod -Uri https://IPADDRESS/resource -Credential $cred
 +           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest)      [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Próbowałem użyć następującego kodu, aby zignorować certyfikat SSL, ale nie jestem pewien, czy faktycznie coś robi.

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

Czy ktoś może udzielić wskazówek, co może tu być nie tak i jak to naprawić?

Dzięki

floyd
źródło
Więc którego używasz? Invoke-RestMethodczy Invoke-WebRequest?
svick
Invoke-WebRequest. Używam go, ponieważ zwraca nagłówki żądań / odpowiedzi w przeciwieństwie do Invoke-RestMethod. Jednak wypróbowałem Invoke-RestMethod, który również przyjmuje identyczne parametry.
floyd
Co jest warte, rzecz ServerValidationCallback jest prawie na pewno czerwonym śledziem, ponieważ błąd, który powinieneś otrzymać, gdy masz problem z walidacją SSL, POWINIEN POWIEDZIEĆ, że: Invoke-WebRequest : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. Możesz spróbować zbadać $ Error [0] .Exception.InnerException, aby uzyskać więcej informacji .. ,
Jaykul,

Odpowiedzi:

179

To obejście zadziałało dla mnie: http://connect.microsoft.com/PowerShell/feedback/details/419466/new-webserviceproxy-needs-force-parameter-to-ignore-ssl-errors

Zasadniczo w skrypcie PowerShell:

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

$result = Invoke-WebRequest -Uri "https://IpAddress/resource"
Lee Grissom
źródło
9
Uwaga, ta odpowiedź jest poprawna; jednak uwaga zawarta w innej odpowiedzi ( stackoverflow.com/a/25163476/68432 ) jest również ważna. To rozwiązanie nie zadziała, jeśli wcześniej wykonałeś "[System.Net.ServicePointManager] :: ServerCertificateValidationCallback = {$ true}".
Paul Suart
Musisz dodać sprawdzenie warunku typu zgodnie z odpowiedzią Arthura Strutzenberga poniżej, w przeciwnym razie pojawi się błąd z informacją, że typ już istnieje
Ralph Willgoss
Czy istnieje zagrożenie bezpieczeństwa podczas używania tego w produkcji?
Amjad
13
5 lat później jest to nadal rozwiązanie dla programu PowerShell 5.1 (pełna wersja .NET Framework). W przypadku programu PowerShell Core jest -SkipCertificateCheckteraz.
evilSnobu
MS wyłączyło Connect, ten link jest nieprawidłowy. Czy jest inny link?
Mark Heath
71

Odpowiedź Lee jest świetna, ale miałem też problemy z obsługiwanymi protokołami.
Po dodaniu następujących wierszy mogłem uzyskać żądanie https. Jak wskazano w tej odpowiedzi https://stackoverflow.com/a/36266735

$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols

Moje pełne rozwiązanie z kodem Lee.

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;
    }
}
"@
$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
AndOs
źródło
czy znalazłeś lepsze rozwiązanie, bo jak masz 40 skryptów to do każdego trzeba to dodać? Wydaje się bez sensu. Przy okazji, dziękuję za odpowiedź
Ender
1
Odpowiedź Lee mi nie pomogła. Musiałem dodać bity, do których się odwołałeś i DZIAŁAŁO!
Pat K
Dziękuję bardzo, określenie protokołów pomogło rozwiązać problem
Alex
1
Dziękuję, dziękuję, dziękuję, że pokazałeś mi SecurityProtocolglobalną właściwość statyczną. Chryste, właśnie straciłem DNI na sprawdzaniu certyfikatów, zaufania, sieci, tras, uprawnień i gówna innych rzeczy, próbując rozwiązać niejasny endpoint does not respondbłąd podczas uzyskiwania dostępu do jednego konkretnego serwera przez https (wszystkie inne działają), tylko dlatego, że ten cholerny PowerShell 5.1 domyślnie SSL3, TLS i TYLKO BLOKUJE GODDAMN TLS11 i TLS12 DOMYŚLNIE Boże, jak bardzo nienawidzę tego gówna Powinienem był napisać ten skrypt w C # / Ruby / C ++ lub czymkolwiek innym, co nie jest PowerShell
quetzalcoatl
1
@StanTastic: Myślę, że nie można trwale zmienić ustawień domyślnych. Myślę, że jest to zakodowane na stałe w kodzie źródłowym ServicePointManager. Nigdy jednak nie sprawdzałem, więc może jest jakiś sposób.
quetzalcoatl
10

Czy próbowałeś użyć System.Net.WebClient?

$url = 'https://IPADDRESS/resource'
$wc = New-Object System.Net.WebClient
$wc.Credentials = New-Object System.Net.NetworkCredential("username","password")
$wc.DownloadString($url)
Sunny Chakraborty
źródło
Sunny, podczas używania tego kodu otrzymuję następujący komunikat: Wyjątek wywołujący „DownloadString” z argumentami „1”: „Serwer zdalny zwrócił błąd: (406) Not Acceptable”. W linii: 4 char: 1 + $ wc.DownloadString ($ url) + ~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo: NotSpecified: (:) [ ], MethodInvocationException + FullyQualifiedErrorId: WebException
floyd
Na podstawie dokumentacji API usługi REST im przy użyciu 406 wskazuje „że nagłówek accept zawarty w żądaniu nie zezwala na odpowiedź XML lub JSON”
floyd
Jakie typy odpowiedzi są dozwolone, jeśli odpowiedzi XML / JSON są niedozwolone?
Sunny Chakraborty
Czy to jest niestandardowa usługa internetowa, której używasz? Czy istnieje publicznie dostępna dokumentacja dotycząca interfejsu API REST?
Sunny Chakraborty
To system biletowy o nazwie EM7. Nie wierzę, że mają publiczne dokumenty. Usługa akceptuje odpowiedź JSON / XML (działa dobrze, jeśli używam cURL). Uważam, że błąd wskazuje, że System.Net.WebClient nie działa?
floyd
10

Alternatywna implementacja w czystym (nie Add-Typestanowi źródło):

#requires -Version 5
#requires -PSEdition Desktop

class TrustAllCertsPolicy : System.Net.ICertificatePolicy {
    [bool] CheckValidationResult([System.Net.ServicePoint] $a,
                                 [System.Security.Cryptography.X509Certificates.X509Certificate] $b,
                                 [System.Net.WebRequest] $c,
                                 [int] $d) {
        return $true
    }
}
[System.Net.ServicePointManager]::CertificatePolicy = [TrustAllCertsPolicy]::new()
Maksymiliana Burszleya
źródło
7

Poniższe zadziałały dla mnie (i wykorzystują najnowsze, nieaktualne środki do interakcji z SSL Certs / funkcją wywołania zwrotnego) i nie próbują ładować tego samego kodu wiele razy w tej samej sesji PowerShell:

if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type)
{
$certCallback=@"
    using System;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    public class ServerCertificateValidationCallback
    {
        public static void Ignore()
        {
            if(ServicePointManager.ServerCertificateValidationCallback ==null)
            {
                ServicePointManager.ServerCertificateValidationCallback += 
                    delegate
                    (
                        Object obj, 
                        X509Certificate certificate, 
                        X509Chain chain, 
                        SslPolicyErrors errors
                    )
                    {
                        return true;
                    };
            }
        }
    }
"@
    Add-Type $certCallback
 }
[ServerCertificateValidationCallback]::Ignore();

Zostało to zaadaptowane z następującego artykułu: https://d-fens.ch/2013/12/20/nobrainer-ssl-connection-error-when-using-powershell/

Arthur Strutzenberg
źródło
5

Okazało się, że kiedy użyłem funkcji this callback do zignorowania certyfikatów SSL [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

Zawsze otrzymywałem komunikat o błędzie, Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send.który brzmi jak wyniki, które masz.

Znalazłem ten post na forum, który doprowadził mnie do poniższej funkcji. Uruchamiam to raz w zakresie mojego innego kodu i działa dla mnie.

function Ignore-SSLCertificates
{
    $Provider = New-Object Microsoft.CSharp.CSharpCodeProvider
    $Compiler = $Provider.CreateCompiler()
    $Params = New-Object System.CodeDom.Compiler.CompilerParameters
    $Params.GenerateExecutable = $false
    $Params.GenerateInMemory = $true
    $Params.IncludeDebugInformation = $false
    $Params.ReferencedAssemblies.Add("System.DLL") > $null
    $TASource=@'
        namespace Local.ToolkitExtensions.Net.CertificatePolicy
        {
            public class TrustAll : System.Net.ICertificatePolicy
            {
                public bool CheckValidationResult(System.Net.ServicePoint sp,System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Net.WebRequest req, int problem)
                {
                    return true;
                }
            }
        }
'@ 
    $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
    $TAAssembly=$TAResults.CompiledAssembly
    ## We create an instance of TrustAll and attach it to the ServicePointManager
    $TrustAll = $TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
    [System.Net.ServicePointManager]::CertificatePolicy = $TrustAll
}

Aaron D.
źródło
2

Invoke-WebRequest „DomainName” -SkipCertificateCheck

Możesz użyć parametru -SkipCertificateCheck, aby osiągnąć to jako polecenie jednowierszowe (TEN PARAMETR JEST OBSŁUGIWANY TYLKO NA PODSTAWIE PSEDYCJI)

Amar Helloween
źródło
1

Próbowałem poszukać dokumentacji na temat EM7 OpenSource REST API. Na razie nie ma szczęścia.

http://blog.sciencelogic.com/sciencelogic-em7-the-next-generation/05/2011

Dużo się mówi o OpenSource REST API, ale nie ma linku do faktycznego API ani jakiejkolwiek dokumentacji. Może byłem niecierpliwy.

Oto kilka rzeczy, które możesz wypróbować

$a = Invoke-RestMethod -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert 
$a.Results | ConvertFrom-Json

Spróbuj tego, aby sprawdzić, czy możesz odfiltrować kolumny, które otrzymujesz z interfejsu API

$a.Results | ft

lub możesz spróbować użyć tego również

$b = Invoke-WebRequest -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert 
$b.Content | ConvertFrom-Json

Nagłówki Curl Style

$b.Headers

Przetestowałem IRM / IWR za pomocą Twittera JSON API.

$a = Invoke-RestMethod http://search.twitter.com/search.json?q=PowerShell 

Mam nadzieję że to pomoże.

Sunny Chakraborty
źródło
Dziękuję za wszelką pomoc. Jednak pierwsze polecenie $ a = Invoke-RestMethod (...) jest tym, które obecnie nie działa dla mnie. Działa dobrze w przypadku witryny HTTP, ale po wprowadzeniu HTTPS, który robi EM7, zwraca opisany błąd. To jest dla Invoke-RestMethod i Invoke-WebRequest. Właśnie używam polecenia cmdlet Invoke-Command i uruchamiam curl.
floyd
0
  1. Uruchom to polecenie

New-SelfSignedCertificate -certstorelocation cert: \ localmachine \ my -dnsname {nazwa-twojej-witryny-hosta}

w programie PowerShell przy użyciu praw administratora spowoduje to wygenerowanie wszystkich certyfikatów w katalogu osobistym

  1. Aby pozbyć się błędu prywatności, wybierz te certyfikaty, kliknij prawym przyciskiem myszy → Kopiuj. I wklej zaufany główny urząd certyfikacji / certyfikaty.
  2. Ostatnim krokiem jest wybranie odpowiednich powiązań w usługach IIS. Przejdź do witryny sieci Web usług IIS, wybierz opcję Powiązania, zaznacz pole wyboru SNI i ustaw indywidualne certyfikaty dla każdej witryny sieci Web.

Upewnij się, że nazwa hosta witryny i nazwa-dns certyfikatu powinny być dokładnie zgodne

Mohit Dharmadhikari
źródło
0

Te ustawienia rejestru wpływają na .NET Framework 4+, a tym samym na PowerShell. Ustaw je i uruchom ponownie wszystkie sesje programu PowerShell, aby korzystać z najnowszego protokołu TLS, bez konieczności ponownego uruchamiania.

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord 

Zobacz https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#schusestrongcrypto

Jeremy Cook
źródło
Dla każdego, kto widzi tę odpowiedź, z naszego doświadczenia wynika, że ​​ta poprawka rejestru w rzeczywistości wymaga ponownego uruchomienia, aby zagwarantować prawidłowe działanie. Podczas próby zapewnienia połączenia TLS 1.2 między komputerem z systemem Windows, na którym jest uruchomiona aplikacja .NET, protokół SSL 3 został pokazany za pośrednictwem śledzenia sieci, który ma być używany z tą wartością rejestru, ale przed ponownym uruchomieniem; Protokół TLS 1.2 został wywołany dopiero po ponownym uruchomieniu.
David W
-1

Jeśli uruchomisz to jako administrator, ten błąd powinien zniknąć

Autonomiczne
źródło