Wie behebt man den Fehler „java.security.cert.CertificateException: Keine alternativen Antragstellernamen vorhanden“?
Lesezeit: 10 Minuten
Dmitrij Pisarenko
Ich habe einen Java-Webservice-Client, der einen Webservice über HTTPS nutzt.
import javax.xml.ws.Service;
@WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...")
public class ISomeService
extends Service
{
public ISomeService() {
super(__getWsdlLocation(), ISOMESERVICE_QNAME);
}
Wenn ich eine Verbindung zur Dienst-URL (https://AAA.BBB.CCC.DDD:9443/ISomeService ), bekomme ich die Ausnahme java.security.cert.CertificateException: No subject alternative names present.
Um es zu beheben, lief ich zuerst openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt und habe folgenden Inhalt in der Datei certs.txt:
CONNECTED(00000003)
---
Certificate chain
0 s:/CN=someSubdomain.someorganisation.com
i:/CN=someSubdomain.someorganisation.com
-----BEGIN CERTIFICATE-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=someSubdomain.someorganisation.com
issuer=/CN=someSubdomain.someorganisation.com
---
No client certificate CA names sent
---
SSL handshake has read 489 bytes and written 236 bytes
---
New, TLSv1/SSLv3, Cipher is RC4-MD5
Server public key is 512 bit
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : RC4-MD5
Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Session-ID-ctx:
Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Key-Arg : None
Start Time: 1382521838
Timeout : 300 (sec)
Verify return code: 21 (unable to verify the first certificate)
---
AFAIK, jetzt muss ich
extrahieren Sie den Teil von certs.txt zwischen -----BEGIN CERTIFICATE----- und -----END CERTIFICATE-----,
Ändern Sie es so, dass der Name des Zertifikats gleich ist AAA.BBB.CCC.DDD und
importieren Sie dann das Ergebnis mit keytool -importcert -file fileWithModifiedCertificate (wo fileWithModifiedCertificate ist das Ergebnis der Operationen 1 und 2).
Ist das richtig?
Wenn ja, wie genau kann ich das Zertifikat aus Schritt 1 mit IP-basierter Adresse (AAA.BBB.CCC.DDD) ?
Update 1 (23.10.2013 15:37 MSK): Als Antwort auf eine ähnliche Frage habe ich folgendes gelesen:
Wenn Sie diesen Server nicht kontrollieren, verwenden Sie seinen Hostnamen (vorausgesetzt, es gibt mindestens einen CN, der mit diesem Hostnamen im vorhandenen Zertifikat übereinstimmt).
Was genau bedeutet “benutzen”?
Beantwortet das deine Frage? Beheben von javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX-Pfadaufbau fehlgeschlagen Fehler?
– Rogerpack
22. Februar 21 um 16:26 Uhr
Dmitrij Pisarenko
Ich habe das Problem behoben, indem ich HTTPS-Prüfungen mit dem vorgestellten Ansatz deaktiviert habe Hier:
Ich habe folgenden Code in die ISomeService Klasse:
static {
disableSslVerification();
}
private static void disableSslVerification() {
try
{
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
Da ich die benutze https://AAA.BBB.CCC.DDD:9443/ISomeService Nur für Testzwecke ist es eine gute Lösung, aber tun Sie dies nicht in der Produktion.
Beachten Sie, dass Sie SSL auch für “eine Verbindung nach der anderen” deaktivieren können, z. B.:
// don't call disableSslVerification but use its internal code:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
httpsConn.setHostnameVerifier(allHostsValid);
httpsConn.setSSLSocketFactory(sc.getSocketFactory());
}
Der im oben genannten Link genannte Zugang scheint blockiert zu sein (nakov.com/blog/2009/07/16/…) . Kann jemand den Link aktualisieren?
– John
30. September 14 um 22:26 Uhr
Ich habe versucht, die Validierung bei diesem Vorgang zu deaktivieren, aber die Browservalidierung für SSL-Protokolle (Poodle-Schwachstelle) gibt mir Folgendes: ssl_error_no_cypher_overlap. Irgendwelche Ideen?
– wird824
28. Mai ’15 um 22:34 Uhr
Das Deaktivieren der HTTPS-Prüfung ist keine “Lösung”. Sie sollten sagen, dass ich einen “Patch” gefunden habe.
– Jus12
16. Mai 16 um 12:51 Uhr
Dies führt zu Sicherheitslücken in Pre_prod und Production. 1. Machen Sie einen Hosteintrag in der Windows-Hostdatei. 2. Oder fügen Sie IP- oder FQDN-Namen in den Feldern für alternative Antragstellernamen in den Zertifikaten hinzu
– Shankar
07.12.18 um 10:00 Uhr
Zertifikatsprüfung und Hostnamenprüfung gibt es aus gutem Grund. Während das Ignorieren aller Warnungen eine Problemumgehung sein kann, ist dies definitiv keine Lösung. Es widersetzt sich jeglicher Sicherheit, die SSL bieten soll.
– Stefan Richter
26. Januar 19 um 21:22 Uhr
juanmhidalgo
Ich habe das gleiche Problem und mit diesem Code gelöst. Diesen Code füge ich vor dem ersten Aufruf meiner Webservices ein.
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
return hostname.equals("localhost"); // or return true
}
});
Oder Sie könnten einfach den gesamten Körper der Funktion verify() durch ersetzen return hostname.equals("localhost");, wenn Sie das möchten. Der if ist völlig überflüssig.
– Nutzer
30. Oktober 15 um 13:49 Uhr
Dies war eine einfache und schnelle Lösung, mit der wir das Testen in der Testumgebung eines Anbieters umgehen konnten, der kein ordnungsgemäßes Zertifikat hatte. Tausend Dank!
– dacDave
8. März 16 um 13:48 Uhr
@JuanM.Hidalgo, das hat bei mir funktioniert, platzierte den obigen Code direkt vor dem Aufruf an HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();. Ignoriert dies auch jedes Zertifikat? Da habe ich gesehen, dass ein solcher Workaround sicherheitsrelevant ist. Danke schön!
– ThunderWiring
2. April 16 um 9:01 Uhr
Diese Antwort löste meine SSL-Zertifikatsausnahme und das Problem mit Nicht-LDH-Zeichen. Ich konnte sehen, dass in Open JDK ein Fehler gemeldet wurde. bugs.openjdk.java.net/browse/JDK-8170265
– Akhil S Kamath
23. August 19 um 9:41 Uhr
Es funktioniert, obwohl es nur zu einem anderen Fehler weitergeht, das Deaktivieren von SSL funktionierte schließlich vollständig, stackoverflow.com/a/19542614/32453
– Rogerpack
22. Februar 21 um 15:51 Uhr
Dies ist eine alte Frage, aber ich hatte das gleiche Problem beim Wechsel von JDK 1.8.0_144 zu jdk 1.8.0_191
Es ist verrückt, aber niemand auf der Welt weiß, was diese Überprüfung tatsächlich verhindert. nur Ingenieure, die Dinge hinzufügen, weil sie es in einem Thoughtworks-Blog gelesen haben
– bharal
22. März 21 um 13:24 Uhr
@bharal Die Überprüfung verhindert Man-in-the-Middle-Angriffe auf Ihre sicheren Verbindungen. Deaktivieren Sie besser nicht die gesamte Zertifikatsüberprüfung, es sei denn, Sie sind sich zu 100 % sicher, dass sie nur in einer Entwicklungsumgebung verwendet wird.
– mvreijn
16. Dezember 21 um 13:48 Uhr
Die Überprüfung der Zertifikatsidentität wird anhand der Anforderungen des Clients durchgeführt.
Wenn Ihr Kunde verwendet https://xxx.xxx.xxx.xxx/something (wo xxx.xxx.xxx.xxx eine IP-Adresse ist), wird die Zertifikatsidentität gegen diese IP-Adresse geprüft (theoretisch nur mit einer IP-SAN-Erweiterung).
Wenn Ihr Zertifikat kein IP-SAN, sondern DNS-SANs hat (oder wenn kein DNS-SAN ein allgemeiner Name im Betreff-DN ist), können Sie dies zum Laufen bringen, indem Sie Ihren Client dazu bringen, stattdessen eine URL mit diesem Hostnamen (oder einem Hostnamen) zu verwenden für die das Zertifikat gültig wäre, wenn es mehrere mögliche Werte gibt). Wenn Ihr Zertifikat beispielsweise einen Namen für hat www.example.combenutzen https://www.example.com/something.
Natürlich benötigen Sie diesen Hostnamen, um zu dieser IP-Adresse aufzulösen.
Wenn DNS-SANs vorhanden sind, wird der CN im Betreff-DN außerdem ignoriert. Verwenden Sie in diesem Fall also einen Namen, der mit einem der DNS-SANs übereinstimmt.
andreycpp
So importieren Sie das Zertifikat:
Extrahieren Sie das Zertifikat vom Server, z openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt Dadurch werden Zertifikate im PEM-Format extrahiert.
Konvertieren Sie das Zertifikat in das DER-Format, da Keytool dies erwartet, z openssl x509 -in certs.txt -out certs.der -outform DER
Jetzt möchten Sie dieses Zertifikat in die Systemstandarddatei „cacert“ importieren. Suchen Sie die Systemstandarddatei „cacerts“ für Ihre Java-Installation. Werfen Sie einen Blick auf Wie erhalte ich den Speicherort von Cacerts der Standard-Java-Installation?
Importieren Sie die Zertifikate in diese cacerts-Datei: sudo keytool -importcert -file certs.der -keystore <path-to-cacerts> Das Standardpasswort für Cacerts lautet „changeit“.
Wenn das Zertifikat für einen FQDN ausgestellt wird und Sie versuchen, eine Verbindung über die IP-Adresse in Ihrem Java-Code herzustellen, sollte dies wahrscheinlich in Ihrem Code behoben werden, anstatt mit dem Zertifikat selbst herumzuspielen. Ändern Sie Ihren Code, um eine Verbindung per FQDN herzustellen. Wenn der FQDN auf Ihrem Entwicklungscomputer nicht auflösbar ist, fügen Sie ihn einfach zu Ihrer Hosts-Datei hinzu oder konfigurieren Sie Ihren Computer mit einem DNS-Server, der diesen FQDN auflösen kann.
„Wenn der FQDN auf Ihrem Entwicklungscomputer nicht auflösbar ist, fügen Sie ihn einfach zu Ihrer Hosts-Datei hinzu“ – geholfen. Vielen Dank!
– Woland
16. November 17 um 16:28 Uhr
Ich habe das gleiche gemacht, aber das Problem besteht weiterhin. Gibt es noch etwas, das mit diesem Ansatz getan werden kann?
– pkgajulapalli
12. Januar 18 um 5:00 Uhr
Eugen
Ich habe dieses Problem richtig behoben, indem ich die Betreff-Alt-Namen im Zertifikat hinzugefügt habe, anstatt Änderungen am Code vorzunehmen oder SSL zu deaktivieren, im Gegensatz zu den anderen Antworten, die hier vorgeschlagen werden. Wenn Sie deutlich sehen, dass die Ausnahme lautet: “Betreff-Alt-Namen fehlen”, also sollte der richtige Weg darin bestehen, sie hinzuzufügen
Der obige Fehler bedeutet, dass Ihrer JKS-Datei die erforderliche Domäne fehlt, auf der Sie versuchen, auf die Anwendung zuzugreifen. Sie müssen Open SSL und das Schlüsseltool verwenden, um mehrere Domänen hinzuzufügen
Kopieren Sie die openssl.cnf in ein aktuelles Verzeichnis
Da das obige Zertifikat selbst signiert und nicht von der CA validiert ist, muss es im Truststore hinzugefügt werden (Cacerts-Datei unten im Speicherort für MAC, für Windows finden Sie heraus, wo Ihr JDK installiert ist.)
„Wenn der FQDN auf Ihrem Entwicklungscomputer nicht auflösbar ist, fügen Sie ihn einfach zu Ihrer Hosts-Datei hinzu“ – geholfen. Vielen Dank!
– Woland
16. November 17 um 16:28 Uhr
Ich habe das gleiche gemacht, aber das Problem besteht weiterhin. Gibt es noch etwas, das mit diesem Ansatz getan werden kann?
– pkgajulapalli
12. Januar 18 um 5:00 Uhr
Möglicherweise möchten Sie nicht die gesamte SSL-Verifizierung deaktivieren und können daher einfach die Überprüfung des Hostnamens deaktivieren, was etwas weniger beängstigend ist als die Alternative:
Wie von conapart3 erwähnt SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER ist jetzt veraltet, daher kann es in einer späteren Version entfernt werden, sodass Sie in Zukunft möglicherweise gezwungen sind, Ihre eigene zu erstellen, obwohl ich immer noch sagen würde, dass ich von allen Lösungen absehen würde, bei denen die gesamte Überprüfung deaktiviert ist.
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER ist jetzt veraltet.
– bonapart3
27. März 17 um 17:35 Uhr
.
8224600cookie-checkWie behebt man den Fehler „java.security.cert.CertificateException: Keine alternativen Antragstellernamen vorhanden“?yes
Beantwortet das deine Frage? Beheben von javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX-Pfadaufbau fehlgeschlagen Fehler?
– Rogerpack
22. Februar 21 um 16:26 Uhr