Comment puis-je utiliser les différents certificats sur des connexions?
Un module que je suis en ajoutant à notre grande application Java a pour converser avec une autre société du SSL site sécurisé. Le problème est que le site utilise un certificat auto-signé. J'ai une copie du certificat pour vérifier que je ne suis pas de la rencontre d'un man-in-the-middle attack, et j'ai besoin d'incorporer ce certificat dans notre code de telle façon que la connexion au serveur sera couronnée de succès.
Voici le code de base:
void sendRequest(String dataPacket) {
String urlStr = "https://host.example.com/";
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setMethod("POST");
conn.setRequestProperty("Content-Length", data.length());
conn.setDoOutput(true);
OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
o.write(data);
o.flush();
}
Sans aucune manipulation supplémentaire mis en place pour le certificat auto-signé, ce meurt à l'âge de conn.getOutputStream() avec l'exception suivante:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Idéalement, mon code doit enseigner Java à accepter cette un certificat auto-signé, pour cette une tache dans l'application, et nulle part ailleurs.
Je sais que je peux importer le certificat dans la JRE de l'autorité de certification magasin, et qui va permettre à Java à l'accepter. Ce n'est pas une approche que je veux prendre si je peux aider; il semble très invasive à faire sur l'ensemble des machines de nos clients pour un module, ils ne peuvent pas utiliser; il aurait une incidence sur toutes les autres applications Java à l'aide de la même JRE, et je n'aime pas que même si les chances de toute autre application Java jamais accès à ce site est nul. Il n'est également pas une opération triviale: sur UNIX, je dois obtenir des droits d'accès pour modifier le JRE de cette façon.
J'ai aussi vu que je peux créer un TrustManager instance qui n'a coutume de les vérifier. Il semble que je pourrais peut-être même créer un TrustManager que les délégués à la vraie TrustManager dans tous les cas, à l'exception de ce seul certificat. Mais il semble que ce TrustManager est installé à l'échelle mondiale, et je présume aurait une incidence sur toutes les autres connexions à partir de notre application, et qui ne sent pas assez bonne pour moi, soit.
Quel est le meilleur, standard, ou le meilleur moyen de mettre en place une application Java pour accepter un certificat auto-signé? Puis-je accomplir tous les objectifs que j'ai à l'esprit ci-dessus, ou vais-je avoir à faire des compromis? Est-il une option impliquant les fichiers et les répertoires et les paramètres de configuration, et peu-à-peu de code?
- petit, de travail correctif: rgagnon.com/javadetails/...
- s'il vous plaît ne pas suggérer cette page. Il désactive la vérification de confiance. Vous allez non seulement accepter le certificat auto-signé que vous voulez, vous êtes aussi à accepter un certificat d'un MITM attaquant va vous présenter avec.
Vous devez vous connecter pour publier un commentaire.
Créer un
SSLSocket
usine vous-même, et de le mettre sur leHttpsURLConnection
avant de les connecter.Vous aurez envie de créer un
SSLSocketFactory
et le garder. Voici un croquis de comment l'initialiser:Si vous avez besoin d'aide pour créer la clé de stockage, s'il vous plaît commentaire.
Voici un exemple de chargement de la clé de stockage:
Pour créer le magasin de clés avec un format PEM certificat, vous pouvez écrire votre propre code à l'aide de
CertificateFactory
, ou tout simplement importer aveckeytool
à partir du JDK (keytool ne de travail pour une "clé d'entrée", mais est parfait pour une "entrée de confiance").KeyStore
(en mémoire) et ajouter la racine de certificats de l'ensemble de vos "vrais" magasins de clés à qui, ou (presque équivalent) créer unSet<TrustAnchor>
à partir de toutes les entrées de votre confiance magasins de clés et de les utiliser pour initialiserPKIXParameters
, et avec qui, à son tour, leTrustManagerFactory
.J'ai lu BEAUCOUP d'endroits en ligne pour résoudre cette chose.
C'est le code que j'ai écrit pour le faire fonctionner:
app.certificateString est une Chaîne qui contient le Certificat, par exemple:
J'ai testé ce que vous pouvez mettre tous les caractères dans le certificat de chaîne, si elle est auto-signé, aussi longtemps que vous gardez la structure exacte ci-dessus. J'ai obtenu le certificat de chaîne avec mon ordinateur portable, Terminal de la ligne de commande.
Si la création d'un
SSLSocketFactory
n'est pas une option, il suffit d'importer la clé dans la JVMRécupérer la clé publique:
$openssl s_client -connect dev-server:443
, puis créer un fichier dev-serveur.pem qui ressemble àImporter la clé:
#keytool -import -alias dev-server -keystore $JAVA_HOME/jre/lib/security/cacerts -file dev-server.pem
.Mot de passe: changeit
Redémarrer JVM
Source: Comment résoudre javax.net.le protocole ssl.SSLHandshakeException?
Nous copier le JRE truststore et ajouter nos certificats personnalisés pour que truststore, puis de dire à l'application d'utiliser la coutume truststore avec un système de la propriété. De cette façon, nous laissez la valeur par défaut JRE truststore seul.
L'inconvénient est que lorsque vous mettez à jour le JRE vous n'obtenez pas de son nouveau truststore automatiquement fusionnées avec votre propre.
Vous pourriez peut-être gérer ce scénario en ayant un programme d'installation ou le démarrage de la routine qui vérifie le truststore/jdk et vérifie une incompatibilité ou automatiquement les mises à jour de la truststore. Je ne sais pas ce qui se passe si vous mettez à jour le truststore alors que l'application est en cours d'exécution.
Cette solution n'est pas 100% élégant ou infaillible, mais il est simple, il fonctionne, et ne nécessite pas de code.
J'ai dû faire quelque chose comme cela lors de l'utilisation de commons-httpclient pour accéder à l'interne un serveur https avec un certificat auto-signé. Oui, notre solution a été de créer un personnalisé TrustManager que simplement passé tout (de l'enregistrement d'un message de débogage).
Cela revient à avoir notre propre SSLSocketFactory qui crée des sockets SSL de notre local SSLContext, qui est seulement à nos locaux TrustManager associés. Vous n'avez pas besoin d'aller près d'un keystore/certstore à tous.
Donc, c'est dans notre LocalSSLSocketFactory:
Le long de avec d'autres méthodes de mise en œuvre de SecureProtocolSocketFactory. LocalSSLTrustManager est celle-ci mannequin de fiducie, le gestionnaire de mise en œuvre.