Ich habe einen Java-Web-Service-Client, der einen Web-Service über HTTPS benötigt.
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 mich mit der Service-URL (https://AAA.BBB.CCC.DDD:9443/ISomeService
) verbinde, erhalte ich die Ausnahme Java.security.cert.CertificateException: No subject alternative names present
.
Um das Problem zu beheben, habe ich zuerst openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
ausgeführt und folgenden Inhalt in der Datei certs.txt
erhalten:
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
certs.txt
zwischen -----BEGIN CERTIFICATE-----
und -----END CERTIFICATE-----
,AAA.BBB.CCC.DDD
und istkeytool -importcert -file fileWithModifiedCertificate
(wobei fileWithModifiedCertificate
das Ergebnis der Operationen 1 und 2 ist).Ist das richtig?
Wenn ja, wie kann ich das Zertifikat von Schritt 1 aus mit IP-basierter Adresse (AAA.BBB.CCC.DDD
) arbeiten lassen?
Update 1 (23.10.2013 15:37 MSK): In einer Antwort auf eine ähnliche Frage habe ich Folgendes gelesen:
Wenn Sie nicht die Kontrolle über diesen Server haben, verwenden Sie seinen Hostnamen (vorausgesetzt, dass Dass mindestens ein CN mit diesem Hostnamen im vorhandenen Cert übereinstimmt).
Was genau bedeutet "verwenden"?
Ich habe das Problem behoben, indem HTTPS-Überprüfungen mit dem hier vorgestellten Ansatz deaktiviert wurden: here :
Ich habe folgenden Code in die ISomeService
-Klasse eingefügt:
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 den https://AAA.BBB.CCC.DDD:9443/ISomeService
nur zu Testzwecken verwende, ist dies eine gute Lösung.
Ich habe das gleiche Problem und mit diesem Code gelöst ... Ich habe diesen Code vor dem ersten Aufruf meiner Webservices eingefügt.
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
return hostname.equals("localhost");
}
});
Es ist einfach und funktioniert gut.
Hier ist die Originalquelle.
Die Überprüfung der Zertifikatidentität wird anhand der Anforderungen des Clients durchgeführt.
Wenn Ihr Client https://xxx.xxx.xxx.xxx/something
verwendet (wobei xxx.xxx.xxx.xxx
eine IP-Adresse ist), wird die Zertifikatidentität gegen diese IP-Adresse geprüft (theoretisch nur unter Verwendung einer IP-Erweiterung SAN).
Wenn Ihr Zertifikat kein IP-SAN, aber DNS-SANs (oder kein DNS-SAN, ein allgemeiner Name im Betreff-DN) hat, können Sie dies erreichen, indem Sie Ihren Client dazu veranlassen, stattdessen eine URL mit diesem Hostnamen (oder einem Hostnamen) zu verwenden für das das Zertifikat gültig wäre, wenn mehrere mögliche Werte vorhanden sind). Wenn Sie für cert beispielsweise einen Namen für www.example.com
haben, verwenden Sie https://www.example.com/something
.
Natürlich benötigen Sie diesen Hostnamen, um diese IP-Adresse aufzulösen.
Wenn DNS-SANs vorhanden sind, wird der CN im Betreff-DN ignoriert. Verwenden Sie in diesem Fall einen Namen, der mit einem der DNS-SANs übereinstimmt.
So importieren Sie das Zertifikat:
openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
Hiermit werden Zertifikate im PEM-Format extrahiert.openssl x509 -in certs.txt -out certs.der -outform DER
Sudo keytool -importcert -file certs.der -keystore <path-to-cacerts>
Das Standard-Kennwort für die Zertifikate lautet 'changeit'.Wenn das Zertifikat für einen vollqualifizierten Domänennamen ausgestellt wird und Sie versuchen, über die IP-Adresse in Ihrem Java-Code eine Verbindung herzustellen, sollte dies wahrscheinlich in Ihrem Code behoben sein, anstatt sich mit dem Zertifikat selbst zu beschäftigen. Ändern Sie Ihren Code, um eine Verbindung per FQDN herzustellen. Wenn FQDN auf Ihrem Dev-Computer nicht auflösbar ist, fügen Sie ihn einfach Ihrer Hosts-Datei hinzu oder konfigurieren Sie Ihren Computer mit einem DNS-Server, der diesen FQDN auflösen kann.
Dies ist eine alte Frage, aber ich hatte das gleiche Problem, als ich von JDK 1.8.0_144 zu Jdk 1.8.0_191 wechselte
Wir haben im Änderungsprotokoll einen Hinweis gefunden:
wir haben die folgenden zusätzlichen Systemeigenschaften hinzugefügt, die in unserem Fall zur Lösung dieses Problems beigetragen haben:
-Dcom.Sun.jndi.ldap.object.disableEndpointIdentification=true
Möglicherweise möchten Sie nicht die gesamte SSL-Verifizierung deaktivieren, und Sie können die Überprüfung des Hostnamens einfach über diese Option deaktivieren, was etwas weniger beängstigend ist als die Alternative:
HttpsURLConnection.setDefaultHostnameVerifier(
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
[BEARBEITEN]
Wie von conapart3 bereits erwähnt, ist SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
jetzt veraltet, daher kann es in einer späteren Version entfernt werden, so dass Sie in Zukunft gezwungen sein werden, selbst zu rollen, obwohl ich immer noch sagen würde, dass ich mich von Lösungen abwenden würde, bei denen die gesamte Überprüfung deaktiviert ist .
mein Problem beim Abrufen dieses Fehlers wurde behoben, indem die vollständige URL "qatest.ourCompany.com/webService" anstelle von "qatest/webService" verwendet wurde. Grund war, dass unser Sicherheitszertifikat einen Platzhalter hatte, d. H. "* .OurCompany.com". Nachdem ich die vollständige Adresse eingegeben hatte, verschwand die Ausnahme. Hoffe das hilft.
Ich habe dieses Problem richtig gelöst, indem ich die Betreffsalternamen im Zertifikat hinzufügte, anstatt Codeänderungen vorzunehmen oder SSL zu deaktivieren, im Gegensatz zu den anderen Antworten, die hier vorgeschlagen werden. Wenn Sie deutlich sehen, dass die Ausnahme "Suject-Alt-Namen fehlt" angezeigt wird, sollten Sie sie hinzufügen
Bitte schauen Sie sich diesen Link an, um Schritt für Schritt zu verstehen .
Der obige Fehler bedeutet, dass in Ihrer JKS-Datei die erforderliche Domäne fehlt, über die Sie auf die Anwendung zugreifen möchten. Sie müssen Open SSL und das Schlüsseltool verwenden, um mehrere Domänen hinzuzufügen
echo '[ subject_alt_name ]' >> openssl.cnf
echo 'subjectAltName = DNS:example.mydomain1.com, DNS:example.mydomain2.com, DNS:example.mydomain3.com, DNS: localhost'>> openssl.cnf
openssl req -x509 -nodes -newkey rsa:2048 -config openssl.cnf -extensions subject_alt_name -keyout private.key -out self-signed.pem -subj '/C=gb/ST=edinburgh/L=edinburgh/O=mygroup/OU=servicing/CN=www.example.com/[email protected]' -days 365
Exportieren Sie die öffentliche Schlüsseldatei (.pem) in das PKS12-Format. Dadurch werden Sie zur Eingabe eines Kennworts aufgefordert
openssl pkcs12 -export -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in
self-signed.pem -inkey private.key -name myalias -out keystore.p12
Erstellen Sie ein.JKS aus einem selbstsignierten PEM (Keystore)
keytool -importkeystore -destkeystore keystore.jks -deststoretype PKCS12 -srcstoretype PKCS12 -srckeystore keystore.p12
Generieren Sie ein Zertifikat über der Keystore- oder JKS-Datei
keytool -export -keystore keystore.jks -alias myalias -file selfsigned.crt
Da das oben genannte Zertifikat selbstsigniert ist und nicht von CA validiert wurde, muss es in Truststore hinzugefügt werden (Cacerts-Datei unterhalb von MAC, bei Windows finden Sie heraus, wo Ihr JDK installiert ist.)
Sudo keytool -importcert -file selfsigned.crt -alias myalias -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts
Originalantwort gepostet auf diesen Link hier .
Ich habe diese Frage nach dieser Fehlermeldung erhalten. In meinem Fall hatten wir jedoch zwei URLs mit unterschiedlichen Subdomains ( http://example1.xxx.com/someservice und http://example2.yyy.com/someservice ), die an dieselbe weitergeleitet wurden Server. Dieser Server hatte nur ein Platzhalterzertifikat für die Domäne * .xxx.com. Wenn der Dienst über die zweite Domäne verwendet wird, stimmt das gefundene Zertifikat (* .xxx.com) nicht mit der angeforderten Domäne (* .yyy.com) überein, und der Fehler tritt auf.
In diesem Fall sollten wir nicht versuchen, eine solche Fehlermeldung durch Verringerung der SSL-Sicherheit zu beheben, sondern den Server und die Zertifikate darauf prüfen.
Habe es schon in https://stackoverflow.com/a/53491151/1909708 beantwortet.
Dies schlägt fehl, da weder der allgemeine Name des Zertifikats (CN
in Zertifizierung Subject
) noch die alternativen Namen (Subject Alternative Name
im Zertifikat) mit dem Zielhostnamen oder der IP-Adresse übereinstimmen.
Wenn Sie beispielsweise von einer JVM aus versuchen, eine Verbindung zu einer IP-Adresse (WW.XX.YY.ZZ
) und nicht zum DNS-Namen ( https://stackoverflow.com ) herzustellen, schlägt die HTTPS-Verbindung fehl, da das Zertifikat im Java Truststore gespeichert ist cacerts
erwartet, dass der allgemeine Name (oder ein alternativer Zertifikatsname wie stackexchange.com oder * .stackoverflow.com usw.) der Zieladresse entspricht.
Bitte überprüfen Sie: https://docs.Oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#HostnameVerifier
HttpsURLConnection urlConnection = (HttpsURLConnection) new URL("https://WW.XX.YY.ZZ/api/verify").openConnection();
urlConnection.setSSLSocketFactory(socketFactory());
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("GET");
urlConnection.setUseCaches(false);
urlConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
});
urlConnection.getOutputStream();
Oben übergeben ein implementiertes HostnameVerifier
-Objekt, das immer true
zurückgibt:
new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
}
Ich war durch 2-Wege-SSL im Springboot. Ich habe alle korrekten Konfigurationsdienst Tomcat-Server und Dienstanrufer RestTemplate gemacht. Aber ich habe den Fehler als "Java.security.cert.CertificateException: Keine alternativen Antragstellernamen vorhanden" erhalten
Nachdem ich die Lösungen durchgearbeitet hatte, stellte ich fest, dass JVM dieses Zertifikat benötigt, da sonst ein Handshake-Fehler auftritt.
Nun, wie man dies zu JVM hinzufügt.
gehen Sie zur Datei jre/lib/security/cacerts. Wir müssen unsere Server-Zertifikatsdatei zu dieser Cacerts-Datei von JVM hinzufügen.
Befehl zum Hinzufügen eines Server-Zertifikats zur Cacerts-Datei über die Befehlszeile in Windows.
C:\Programme\Java\jdk1.8.0_191\jre\lib\security> keytool -import -noprompt -trustcacerts -alias sslserver -datei E:\spring_cloud_sachin\ssl_keys\sslserver.cer -keystore cacerts -storepass changeit
Überprüfen Sie, ob das Server-Zertifikat installiert ist oder nicht:
C:\Programme\Java\jdk1.8.0_191\jre\lib\security> keytool -list -keystore cacerts
sie können eine Liste der installierten Zertifikate sehen:
weitere Informationen: https://sachin4Java.blogspot.com/2019/08/javasecuritycertcertificateexception-no.html
public class RESTfulClientSSL {
static TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
}};
public class NullHostNameVerifier implements HostnameVerifier {
/*
* (non-Javadoc)
*
* @see javax.net.ssl.HostnameVerifier#verify(Java.lang.String,
* javax.net.ssl.SSLSession)
*/
@Override
public boolean verify(String arg0, SSLSession arg1) {
// TODO Auto-generated method stub
return true;
}
}
public static void main(String[] args) {
HttpURLConnection connection = null;
try {
HttpsURLConnection.setDefaultHostnameVerifier(new RESTfulwalkthroughCer().new NullHostNameVerifier());
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
String uriString = "https://172.20.20.12:9443/rest/hr/exposed/service";
URL url = new URL(uriString);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
//connection.setRequestMethod("POST");
BASE64Encoder encoder = new BASE64Encoder();
String username = "admin";
String password = "admin";
String encodedCredential = encoder.encode((username + ":" + password).getBytes());
connection.setRequestProperty("Authorization", "Basic " + encodedCredential);
connection.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
StringBuffer stringBuffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
stringBuffer.append(line);
}
String content = stringBuffer.toString();
System.out.println(content);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}
fügen Sie den Host-Eintrag mit der IP hinzu, die dem CN im Zertifikat entspricht
CN = someSubdomain.someorganisation.com
aktualisieren Sie nun die IP-Adresse mit dem CN-Namen, unter dem Sie auf die URL zugreifen möchten.
Es hat bei mir funktioniert.