J'essaie de me connecter à l'un de mes serveurs via SSL, avec Java. J'ai essayé beaucoup d'options ici, c'est mon meilleur essai:
Je génère un jssecacerts avec le script recommendet: http://blogs.Oracle.com/andreas/resource/InstallCert.Java avec la commande: Java InstallCert ssl. someUrl.de changeit
après cela, j'ai fait la commande une deuxième fois:
Loading KeyStore jssecacerts...
Opening connection to ssl.someUrl.de:443...
Starting SSL handshake...
No errors, certificate is already trusted
Server sent 1 certificate(s):
1 Subject [email protected], CN=plesk, OU=Plesk, O=Parallels, L=Hernd
on, ST=Virginia, C=US
Issuer [email protected], CN=plesk, OU=Plesk, O=Parallels, L=Hernd
on, ST=Virginia, C=US
sha1 f1 0d 2c 54 05 e1 32 19 a0 52 5e e1 81 6c a3 a5 83 0d dd 67
md5 f0 b3 be 5e 5f 6e 90 d1 bc 57 7a b2 81 ce 7d 3d
Enter certificate to add to trusted keystore or 'q' to quit: [1]
J'ai copié le fichier dans le répertoire par défaut et j'ai chargé le certificat dans Java trustStore
System.setProperty("javax.net.ssl.trustStore", "C:\\Program Files (x86)\\Java\\jre6\\lib\\security\\jssecacerts");
System.setProperty("javax.net.ssl.trustStorePassword","changeit");
Ensuite j'essaye de me connecter
URL url = new URL("https://ssl.someUrl.de/");
URLConnection conn = url.openConnection();
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Et j'obtiens une erreur sur la 3ème ligne: (Aucun nom correspondant à ssl.someUrl.de trouvé)
javax.net.ssl.SSLHandshakeException: Java.security.cert.CertificateException: No name matching ssl.someUrl.de found
Est-ce la cause du certificat plesk par défaut ou quelque chose d'autre ne va pas?
Configuration: JRE 6.20, Netbeans 6.8, Windows7 64 bits
Il semble que le certificat du serveur auquel vous essayez de vous connecter ne correspond pas à son nom d'hôte.
Lorsqu'un client HTTPS se connecte à un serveur, il vérifie que le nom d'hôte dans le certificat correspond au nom d'hôte du serveur. Il ne suffit pas de faire confiance à un certificat, il doit également correspondre au serveur avec lequel vous souhaitez parler. (Par analogie, même si vous faites confiance à un passeport pour être légitime, vous devez toujours vérifier qu'il s'agit bien de la personne à laquelle vous voulez parler, et pas seulement de tout passeport auquel vous auriez confiance pour être légitime.)
En HTTP, cela se fait en vérifiant que:
le certificat contient un autre nom de sujet DNS (il s'agit d'une extension standard) correspondant au nom d'hôte;
à défaut, le dernier CN de votre nom distinctif de sujet (c'est le nom principal si vous le souhaitez) correspond au nom d'hôte. (Voir RFC 2818.)
Il est difficile de dire quel est le nom alternatif du sujet sans avoir le certificat (bien que, si vous vous connectez avec votre navigateur et vérifiez son contenu plus en détail, vous devriez pouvoir le voir.) Le nom distinctif du sujet semble être:
[email protected], CN=plesk, OU=Plesk, O=Parallels, L=Herndon, ST=Virginia, C=US
(Il faudrait donc que ce soit CN = ssl.someUrl.de au lieu de CN = plesk, si vous n'avez pas déjà un autre nom de sujet avec DNS: ssl.someUrl.de; je suppose que non.)
Vous pourrez peut-être contourner la vérification du nom d'hôte à l'aide de HttpsURLConnection.setHostnameVerifier (..) . Il ne devrait pas être trop difficile d'écrire un HostnameVerifier personnalisé qui contourne la vérification, bien que je suggère de le faire uniquement lorsque le certificat est celui qui est spécifiquement concerné ici. Vous devriez pouvoir l'obtenir en utilisant l'argument SSLSession et sa méthode getPeerCertificates ().
(De plus, vous n'avez pas besoin de définir les propriétés javax.net.ssl. * Comme vous l'avez fait, car vous utilisez quand même les valeurs par défaut.)
Alternativement, si vous contrôlez le serveur auquel vous vous connectez et son certificat, vous pouvez en créer un certificat qui correspond aux règles de dénomination ci-dessus (le CN devrait être suffisant, bien que le nom alternatif soumis soit une amélioration). Si un certificat auto-signé est assez bon pour ce que vous nommez, assurez-vous que son nom commun (CN) est le nom d'hôte auquel vous essayez de parler (pas l'URL complète, juste le nom d'hôte).
Dans Java 8, vous pouvez ignorer la vérification du nom du serveur avec le code suivant:
HttpsURLConnection.setDefaultHostnameVerifier ((hostname, session) -> true);
Cependant, cela ne doit être utilisé que dans le développement!
J'ai créé une méthode fixUntrustCertificate (), donc lorsque je traite avec un domaine qui n'est pas dans des autorités de certification de confiance, vous pouvez appeler la méthode avant la demande. Ce code fonctionnera après Java1.4. Cette méthode s'applique à tous les hôtes:
public void fixUntrustCertificate() throws KeyManagementException, NoSuchAlgorithmException{
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) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new Java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// set the allTrusting verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
J'ai trouvé une bonne résolution ici: http://www.mkyong.com/webservices/jax-ws/Java-security-cert-certificateexception-no-name-matching-localhost-found/
Mais mon problème était un peu différent et l'a résolu différemment.
Le service Web était sur l'hôte distant. Par exemple: https://some.remote.Host/MyWebService?wsdl
Mais il n'était disponible que par IP pour tous les clients, mais un certificat a été créé pour le domaine: some.remote.Host (CN = some.remote.Host). Et ce domaine ne peut pas être résolu par IP car il n'est pas présenté dans DNS).
Donc, le même problème est apparu: si j'utilise IP pour me connecter au service Web par SSL, il ne peut pas être atteint car le certificat CN = some.remote.Host et ce n'est pas égal au nom d'hôte que j'ai spécifié (c.-à-d. IP hôte) .
Je l'ai résolu en faisant correspondre ce nom d'hôte avec IP dans le fichier/etc/hosts. Le problème a été corrigé.
Mais dans le cas où le service Web est hébergé sur le serveur d'application localhost, il pense que cela devrait être résolu comme mkyong décrit dans son article.
Si vous recherchez une erreur Kafka, cela peut être dû à la mise à niveau de la version de Kafka de 1.x vers 2.x.
javax.net.ssl.SSLHandshakeException: problème général SSLEngine ... javax.net.ssl.SSLHandshakeException: problème général SSLEngine ... Java.security.cert.CertificateException: aucune correspondance de nom *** trouvée
ou
[Producer clientId = producteur-1] La connexion au nœud -2 a échoué l'authentification en raison de: Échec de l'établissement de la liaison SSL
La valeur par défaut de ssl.endpoint.identification.algorithm a été remplacée par https, qui effectue la vérification du nom d'hôte (des attaques man-in-the-middle sont possibles sinon). Définissez ssl.endpoint.identification.algorithm sur une chaîne vide pour restaurer le comportement précédent. Apache Kafka Changements notables dans 2.0.
Solution: SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, ""
Le nom du serveur doit être le même que le prénom/nom que vous donnez lors de la création d'un certificat