6 votes

Erreur Java HttpClient pour absence de certificat SSL, utilisation du certificat en tant que chaîne dans le code ?

Je suis un peu perdu en essayant d'utiliser HttpClient pour appeler un site https qui utilise un certificat auto-signé. J'ai le code comme ci-dessous, qui me permet d'effectuer l'appel, mais j'obtiens l'erreur suivante javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found J'ai téléchargé le certificat depuis mon navigateur web et je comprends que je peux l'importer dans le keystore, mais je préférerais l'insérer dans le code et l'utiliser de cette façon, y a-t-il un moyen de le faire ?

    HttpClient client = new HttpClient();

    EasySSLProtocolSocketFactory easySSLProtocolSocketFactory = new EasySSLProtocolSocketFactory();
    Protocol https = new Protocol("https", easySSLProtocolSocketFactory,
            443);
    Protocol.registerProtocol("https", https);

    BufferedReader br = null;

    String responseString = "";

    GetMethod method = new GetMethod(path);

    int returnCode = client.executeMethod(method);

4voto

Bruno Points 47560

En supposant que votre certificat soit au format PEM. Vous pouvez l'intégrer dans le code et utiliser Château gonflable 's PEMReader pour le transformer en X509Certificate instance. Une fois que c'est fait, créez un KeyStore en mémoire et y placer ce certificat X.509. Ensuite, instanciez une nouvelle instance SSLContext en utilisant cela KeyStore en tant que registre de confiance et faire en sorte que votre client HTTP l'utilise.

Cela ressemblerait à ceci (pas essayé, n'oubliez pas de fermer les lecteurs et d'attraper les exceptions...) :

PEMReader pemReader = new PEMReader(new StringReader("----- BEGIN ......");
X509Certificate cert = (X509Certificate) pemReader.readObject();

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry("some name", cert);

TrustManagerFactory tmf = TrustManagerFactory.getInstance(
    TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, tmf.getTrustManagers(), null);

Ensuite, utilisez ceci SSLContext pour votre connexion. Vous pouvez le faire avec la fonction SSLSocketFactory si vous utilisez la version 4.x (ou este si vous utilisez la version 3.x). Je suggère d'utiliser Apache HttpClient 4.x de nos jours.

2voto

Sur la base de la réponse de Alexander Chzhen et pour HttpClient 4.3 je crée d'abord un contexte qui fait confiance à tous :

SSLContextBuilder sslctxb = new SSLContextBuilder();

sslctxb.loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()),
                          new TrustSelfSignedStrategy() {
  @Override
  public boolean isTrusted(X509Certificate[] chain,
                           String            authType)
    throws CertificateException {
    return true;
  }
});

SSLContext sslctx = sslctxb.build();

Ensuite, le client bâtisseur :

HttpClientBuilder hcb = HttpClients.custom();

et je ne fais que définir le contexte. Je n'utilise pas de setSSLSocketFactory parce qu'il interfère avec setHostnameVerifier ci-dessous :

hcb.setSslcontext(sslctx);

Enfin, j'ai mis en place un vérificateur de nom d'hôte qui vérifie tous les noms d'hôte :

hcb.setHostnameVerifier(new X509HostnameVerifier() {
  @Override
  public void verify(String host, SSLSocket ssl)
    throws IOException {
  }

  @Override
  public void verify(String host, X509Certificate cert)
    throws SSLException {
  }

  @Override
  public void verify(String host, String[] cns, String[] subjectAlts)
    throws SSLException {
  }

  @Override
  public boolean verify(String hostname, SSLSession session) {
    return true;
  }
});

Enfin, construire le client :

HttpClient c = hcb.build();

1voto

Ralph Points 42744

Si vous souhaitez accepter ce seul certificat et non tous les certificats auto-signés, vous devez télécharger le certificat et stocker le fichier pem quelque part.

Vous pouvez maintenant utiliser ce code pour charger le fichier pem créez un nouvel espace de confiance avec ce certificat et utilisez l'espace de confiance pour votre fichier HttpClient .

//use java. ... .X509Certificate, not javax. ... .X509Certificate
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

@Test
public void testSslCertificate()
        throws IOException, KeyStoreException, NoSuchAlgorithmException,
               CertificateException, KeyManagementException {

    X509Certificate cert;
    try (FileInputStream pemFileStream = new FileInputStream(newFile("your.pem"))) {
        CertificateFactory certFactory = CertificateFactory.getInstance("X509");
        cert = (X509Certificate) certFactory.generateCertificate(pemFileStream);
    }

    //create truststore
    KeyStore trustStore = KeyStore.getInstance("JKS");
    trustStore.load(null); //create an empty trustore

    //add certificate to truststore - you can use a simpler alias
    String alias = cert.getSubjectX500Principal().getName() + "["
            + cert.getSubjectX500Principal().getName().hashCode() + "]";
    trustStore.setCertificateEntry(alias, cert);

    //configure http client
    TrustManagerFactory trustManagerFactory =
       TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(trustStore);

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

    HttpClientBuilder httpClientBuilder = HttpClientBuilder.
                                          create().setSslcontext(sslContext);

    try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
        HttpGet httpGetRequest = new HttpGet("https://yourServer");
        try (CloseableHttpResponse httpResponse =
                            httpClient.execute(httpGetRequest)) {
            Assert.assertEquals(200,
                                httpResponse.getStatusLine().getStatusCode());
        }
    }
}

0voto

Alexander Chzhen Points 1302

Voici comment rendre Apache HttpClient 4.3 capable d'accepter des certificats auto-signés :

HttpClientBuilder cb = HttpClientBuilder.create();
SSLContextBuilder sslcb = new SSLContextBuilder();
sslcb.loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()),
                        new TrustSelfSignedStrategy());
cb.setSslcontext(sslcb.build());
HttpClient client = cb.build()

Pour exécuter des requêtes POST ou GET, utilisez la méthode d'exécution standard :

HttpResponse response = client.execute(...);

Rappel : Vous êtes vulnérable lorsque vous faites confiance à un certificat auto-signé.

0voto

D.W. Points 805

Dans de nombreuses situations, l'épinglage de certificats peut être préférable au codage en dur d'un certificat particulier.

Oui, vous pouvez intégrer un certificat en dur dans votre code, et cela fonctionnera et sera sécurisé. C'est une approche parfaitement raisonnable. Cependant, elle présente certains inconvénients. L'un d'entre eux est que ce certificat finira par expirer et que votre application cessera de fonctionner. De plus, si vous souhaitez modifier votre clé privée, vous ne pourrez pas le faire.

Par conséquent, dans de nombreux scénarios, l'utilisation de l'épinglage de certificats est plus souple et peut être préférable. Voir aussi aquí pour obtenir des références sur la manière de mettre en œuvre l'épinglage de certificats.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X