Powershell und Zertifikate
Ich liebe PowerShell und insbesondere Invoke-Webrequest und Invoke-RESTMethod. Aber beide prüfen per Default die Gültigkeit der Zertifikate. Das ist im Prinzip richtig aber in Testumgebungen manchmal auch störend, wenn die Gegenseite eben kein gültiges Zertifikate hat. SO kann ich die Prüfung für die aktuelle Session abschalten.
Hinweis:
In der neuen PWSH gibt es bei Invoke-Webrequest und
Invoke-Restmethod den Parameter "SkipCertificateCheck"
Der Fehler in Reinform
Ich habe dazu einen WebServer (in meinem Fall PRTG) mit einem selbstsignierten Zertifikat im LAN und wollte einfach eine Webseite abrufen. ein "Invoke-Webrequest" schlägt natürlich fehl mit dem Fehler:
Invoke-WebRequest : Die zugrunde liegende Verbindung wurde geschlossen: Für den geschützten SSL/TLS-Kanal konnte keine Vertrauensstellung hergestellt werden..
PS C:\> Invoke-WebRequest https://192.168.13.14 Invoke-WebRequest : Die zugrunde liegende Verbindung wurde geschlossen: Für den geschützten SSL/TLS-Kanal konnte keine Vertrauensstellung hergestellt werden..
In der PowerShell ist das Fenster rot und eine Exception wird gestartet:
Ich kann den Fehler per Try/Catch (Siehe auch PowerShell Error Handling) abfangen aber die Daten der Webseite bekomme ich so doch nicht. Ich muss also meinen Code anweisen, das gelieferte Zertifikat zu akzeptieren. Dazu gibt es je nach PowerShell-Version und genutzte API verschiedene Optionen:
SSL-Check generell abschalten
Über folgenden Einzeiler können Sie im Skript bei allen PowerShell-Versionen die Prüfung für alle Zertifikate abschalten.
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
Technisch wird die Funktion des ServicePointManager zur Verifizierung des Zertifikats so verändert, dass Sie immer ein "$true" liefert. Normalerweise steht da "$null" drin und die Funktion prüft, ob der gelieferte Name auch mit dem angefragten Namen übereinstimmt.
- ServicePointManager.ServerCertificateValidationCallback Property
https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepointmanager.servercertificatevalidationcallback - RemoteCertificateValidationCallback Delegate
https://docs.microsoft.com/en-us/dotnet/api/system.net.security.remotecertificatevalidationcallback - LocalCertificateSelectionCallback Delegate
https://docs.microsoft.com/en-us/dotnet/api/system.net.security.localcertificateselectioncallback
SSL-Prüfung abschalten (Langform)
Nun funktionieren diese Aufrufe so, dass Sie im Fehlerfall eine "Callback"-Funktion aufrufen, die dem Modul die weitere Verarbeitung vorgibt. Per Default wird hier dann ein Fehler ausgegeben. Wenn ich das umgehen will, muss ich einfach eine eigene Funktion bereitstellen, die in dem Fall aufgerufen wird und ein beschwichtigendes OK liefert. Hier der entsprechende Code dazu:
Write-host "Disable Certificate checks" Add-Type @" using System; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; public class ServerCertificateValidationCallback { public static void Ignore() { ServicePointManager.ServerCertificateValidationCallback += delegate ( Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors ) { return true; }; } } "@ [ServerCertificateValidationCallback]::Ignore();
Leider geht das nicht allein mit Powershell. Über den "Add-Type"-Befehl wird etwas C#-Code als Klasse "ServerCertificateValidationCallback" mit einer Methode "Ignore" definiert und aufgerufen. Dieses Beispiel gibt einfach "True" zurück und damit vertraue ich nun innerhalb dieses Skripts allen Zertifikaten:
Achtung: Damit hebeln Sie natürlich alle Schutzfunktionen aus und können nicht mehr sicher sein, dass Sie auf dem richtigen Server gelandet sind und niemand sich als "Man in the Middle" eingeschliffen hat. Dieses Vorgehen ist während der Entwicklung und Tests tolerierbar aber nicht mehr im Betrieb und erst recht nicht bei Verbindungen über ungesicherte Leitungen, insbesondere Internet oder zu Cloud-Anbietern.
- PowerShell, HTTPS/SSL, and Self-Signed
Certificates
https://grumpyneteng.com/powershell-httpsssl-and-self-signed-certificates/
Gleicher Abruf noch mal
Mit diesen Vorarbeiten klappt dann auch der Abruf trotz ungültigen Zertifikat.
Leider hat Microsoft in der PowerShell 1.0-5.0 den Commandlets "Invoke-WebRequest" und "Invoke-RestMethod" keinen Parameter spendiert, der die SSL-Prüfung steuert.
Hinweis:
In der neuen PWSH gibt es bei Invoke-Webrequest und
Invoke-Restmethod den Parameter "SkipCertificateCheck"
PowerShell SkipCertificateCheck
Mit PowerShell Core hat Microsoft die beiden Commandlets "Invoke-Webrequest" und "Invoke-RestMethod" mit dem Parameter SkipCertificateCheck versehen.
- Invoke-Webrequest
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?parameters - Invoke-RestMethod
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?parameters
Damit schalten Sie für diesen einen Aufruf alle Prüfungen ab, d.h. die Prüfung auf Name, SAN-Name, Gültigkeitsdauer, RootCA, Rückrufliste etc. Microsoft addiert aber hier zurecht den deutlichen Hinweis:
Using this parameter is not secure and is not recommended. This switch is only
intended to be used against known hosts using a self-signed certificate for
testing purposes. Use at your own risk.
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-7.2#parameters
Sie können das daher gerne für interne Tests in einem 100% vertrauenswürdigen Netzwerk nutzen. Aber schauen Sie schon dazu, dass die Zertifikate der Gegenstelle auf ihrem System dann doch "vertrauenswürdig" sind. Das muss ja kein "gekauftes" Zertifikat sein. Die gibt es eh nur für öffentliche DNS-Namen, die auch ihnen gehören aber nicht für IP-Adressen oder interne Namen. Es ist aber relativ einfach eine kleine PKI zu betreiben, mit der sie interne Webserver-Zertifikate ausstellen. Sie müssen dann nur diese RootCA auf ihren eigenen Systemen als "Trusted" addieren.
Verbindungszertifikat ermitteln
Eine weitere nützliche Funktion habe ich in der PowerShell 2-5 gefunden, die in der PowerShell 6/7 wohl nicht mehr möglich ist. Wenn ich eine HTTPS-Verbindung aufbaue, dann "speichert" der WINHTTP-Stack die Verbindung im Cache und auch diese Daten kann ich abrufen. Sie können das einfach ausprobieren.
PS C:\> $msxfaq=Invoke-WebRequest https://www.msxfaq.de PS C:\> $servicepoint=[System.Net.ServicePointManager]::FindServicePoint("https://www.msxfaq.de") PS C:\> $servicepoint BindIPEndPointDelegate : ConnectionLeaseTimeout : -1 Address : https://www.msxfaq.de/ MaxIdleTime : 100000 UseNagleAlgorithm : True ReceiveBufferSize : -1 Expect100Continue : False IdleSince : 01.02.2023 13:48:09 ProtocolVersion : 1.1 ConnectionName : https ConnectionLimit : 2 CurrentConnections : 1 Certificate : System.Security.Cryptography.X509Certificates.X509Certificate ClientCertificate : SupportsPipelining : True
Interessant ist hier das Property "Certificate", welches mir das vom Server angebotene Zertifikat anzeigt. Allerdings hier erst einmal nur wenige Felder
PS C:\> $servicepoint.Certificate | fl Handle : 1903624418016 Issuer : CN=Starfield Secure Certificate Authority - G2, OU=http://certs.starfieldtech.com/repository/, O="Starfield Technologies, Inc.", L=Scottsdale, S=Arizona, C=US Subject : CN=www.msxfaq.de
Die anderen Informationen werden nicht als Property sondern als Methode herausgeführt und müssen daher individuell ausgelesen werden.
PS C:\> $servicepoint.Certificate | gm TypeName: System.Security.Cryptography.X509Certificates.X509Certificate Name MemberType Definition ---- ---------- ---------- Dispose Method void Dispose(), void IDisposable.Dispose() Equals Method bool Equals(System.Object obj), bool Equals(X509Certificate other) Export Method byte[] Export(System.Security.Cryptography.X509Certificates.X509ContentType ... GetCertHash Method byte[] GetCertHash(), byte[] GetCertHash(System.Security.Cryptography.HashAl... GetCertHashString Method string GetCertHashString(), string GetCertHashString(System.Security.Cryptog... GetEffectiveDateString Method string GetEffectiveDateString() GetExpirationDateString Method string GetExpirationDateString() GetFormat Method string GetFormat() GetHashCode Method int GetHashCode() GetIssuerName Method string GetIssuerName() GetKeyAlgorithm Method string GetKeyAlgorithm() GetKeyAlgorithmParameters Method byte[] GetKeyAlgorithmParameters() GetKeyAlgorithmParametersString Method string GetKeyAlgorithmParametersString() GetName Method string GetName() GetObjectData Method void ISerializable.GetObjectData(System.Runtime.Serialization.SerializationI... GetPublicKey Method byte[] GetPublicKey() GetPublicKeyString Method string GetPublicKeyString() GetRawCertData Method byte[] GetRawCertData() GetRawCertDataString Method string GetRawCertDataString() GetSerialNumber Method byte[] GetSerialNumber() GetSerialNumberString Method string GetSerialNumberString() GetType Method type GetType() Import Method void Import(byte[] rawData), void Import(byte[] rawData, string password, Sy... OnDeserialization Method void IDeserializationCallback.OnDeserialization(System.Object sender) Reset Method void Reset() ToString Method string ToString(), string ToString(bool fVerbose) Handle Property System.IntPtr Handle {get;} Issuer Property string Issuer {get;} Subject Property string Subject {get;} PS C:\> $servicepoint.Certificate.GetCertHashString() 04997EC3766D6F513820911A313A18D4A0040E20
So können Sie auch mit Invoke-WebRequest quasi nachträglich schauen, welche TLS-Eigenschaften die Verbindung hatte
- ServicePointManager Klasse
https://learn.microsoft.com/de-de/dotnet/api/system.net.servicepointmanager?view=net-7.0
Weitere Links
- PS HTTPClient
- PowerShell und SOAP
- PowerShell Error Handling
- Ignoring SSL trust in PowerShell
System.Net.WebClient
https://blogs.technet.microsoft.com/bshukla/2010/04/12/ignoring-ssl-trust-in-powershell-system-net-webclient/ - Windows PowerShell, Invalid Certificates,
and Automated Downloading
https://blogs.technet.microsoft.com/heyscriptingguy/2010/07/25/windows-powershell-invalid-certificates-and-automated-downloading/ -
ServicePointManager.ServerCertificateValidationCallback-Eigenschaft
https://msdn.microsoft.com/de-de/library/system.net.servicepointmanager.servercertificatevalidationcallback(v=vs.110).aspx -
HttpWebRequest.ServerCertificateValidationCallback-Eigenschaft
https://msdn.microsoft.com/de-de/library/system.net.httpwebrequest.servercertificatevalidationcallback(v=vs.110).aspx -
PowerShell, HTTPS/SSL, and Self-Signed
Certificates
https://grumpyneteng.com/powershell-httpsssl-and-self-signed-certificates/