Fehlermeldung
The remote certificate was rejected by the provided RemoteCertificateValidationCallback.
Stabiler Text in .NET Core und .NET 5–10; HttpClient verpackt den Fehler in „The SSL connection could not be established, see inner exception.“ Der Wert von SslPolicyErrors, der an den Callback übergeben wird, zeigt dir, ob auch .NET selbst ein Problem gefunden hat.
.NET SslStream / HttpClient — a custom validation callback returned false
Was der Fehler bedeutet
Die Anwendung hat einen eigenen Callback zur Zertifikatsvalidierung installiert (ServerCertificateCustomValidationCallback oder RemoteCertificateValidationCallback), und dieser Callback hat false zurückgegeben. Die eingebauten Prüfungen von .NET waren womöglich erfolgreich; dein Code hat entschieden, das Zertifikat abzulehnen. Typisch beim Pinning von Zertifikaten oder Schlüsseln, nachdem das Zertifikat des Servers erneuert oder rotiert wurde.
Warum der Fehler auftritt
Das gepinnte Zertifikat wurde ersetzt
häufigDas Pinning des Thumbprints eines Zertifikats scheitert bei jeder Erneuerung (bei öffentlichen CAs inzwischen alle paar Monate); das neue Zertifikat hat einen neuen Hash.
Die eigene Logik des Callbacks lehnt gültige Zertifikate ab
häufigPrüfungen auf einen exakten Ausstellernamen, ein Subject oder eine Thumbprint-Liste, die nicht mehr passen, oder Bedingungen, die die im Argument errors übergebenen Fehler ignorieren.
Der Callback lehnt zu Recht ein echtes Problem ab
gelegentlichEin Callback, der errors == SslPolicyErrors.None zurückgibt, lehnt nicht vertrauenswürdige, abgelaufene oder nicht passende Zertifikate ab; die Ursache ist dann das Zertifikat selbst.
So behebst du den Fehler
- 1.
Loggen, was der Callback sieht
Zeichne im Callback SslPolicyErrors, Subject, SHA-256-Thumbprint und Ablaufdatum auf und aktualisiere dann die Pin-Liste oder korrigiere das Zertifikat.
csharp ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => { var thumbprint = cert!.GetCertHashString(HashAlgorithmName.SHA256); logger.LogWarning("TLS {Host}: errors={Errors} subject={Subject} sha256={Thumb} notAfter={NotAfter:u}", request.RequestUri?.Host, errors, cert.Subject, thumbprint, cert.NotAfter); return errors == SslPolicyErrors.None && pinnedThumbprints.Contains(thumbprint); }, - 2.
Öffentlichen Schlüssel pinnen und einen Backup-Pin vorhalten
SPKI-Pins bleiben über Erneuerungen hinweg gültig, die den Schlüssel wiederverwenden; pinne immer mindestens einen Backup-Schlüssel, damit eine Rotation die Clients nicht aussperrt.
bash # Pin the public key (SPKI) rather than the certificate: it survives renewals with the same key openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null \ | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64