web-dev-qa-db-ja.com

JavaでSSL証明書エラーを無視する

Apache Httpクライアント。あなたは関連するコードを見ることができます ここ

String url = "https://path/to/url/service";
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(url);

// Test whether to ignore cert errors
if (ignoreCertErrors){
  TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager(){
      public X509Certificate[] getAcceptedIssuers(){ return null; }
      public void checkClientTrusted(X509Certificate[] certs, String authType) {}
      public void checkServerTrusted(X509Certificate[] certs, String authType) {}
    }
  };

  try {
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustAllCerts, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
  } catch (Exception e){
    e.printStackTrace();
  }
}

try {

  // Execute the method (Post) and set the results to the responseBodyAsString()
  int statusCode = client.executeMethod(method);
  resultsBody = method.getResponseBodyAsString();

} catch (HttpException e){
  e.printStackTrace();
} catch (IOException e){
  e.printStackTrace();
} finally {
  method.releaseConnection();
}

これは、SSL証明書エラーを無視するために誰もが使用する方法と言われています(ステージング用に設定するだけで、本番環境では使用されません)。しかし、私はまだ次の例外/スタックトレースを取得しています:

javax.net.ssl.SSLHandshakeException: Sun.security.validator.ValidatorException: PKIX path building unable to find valid certification path to requested target

どんなヒントも素晴らしいでしょう。 TrustManagerを間違って実行している場合、またはHTTP Postメソッドを別の方法で実行する必要がある場合。

ありがとう!

9
andrewpthorp

まず、証明書エラーを無視無視しません。代わりに対処してください。証明書エラーを無視すると、潜在的なMITM攻撃への接続が開かれます。それは時々それが音を立てるのであなたの煙警報器のブザーをオフにするようなものです...

確かに、それはテストコード専用であると言いたくてたまらなく、最終的には本番にはなりませんが、締め切りが近づくと何が起こるかは誰でも知っています。テスト中にコードにエラーが表示されない->出荷可能そのまま。必要に応じて、代わりにテストCAをセットアップする必要があります。作成するのはそれほど難しくなく、プロセス全体は、開発用のカスタムコードを導入して本番環境で削除するよりも難しくありません。

あなたは明らかにApache Http Clientを使用しています:

HttpClient client = new HttpClient();
int statusCode = client.executeMethod(method);

ただし、作成したSSLContextを使用してjavax.net.ssl.HttpsURLConnectionを初期化しています。

HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

これは、Apache Http Clientの設定から完全に独立しています。

代わりに、Apache Http Clientライブラリ用にSSLContextを設定する必要があります this answer で説明されています。 Apache Http Client 3.xを使用している場合は、独自のSecureProtocolSocketFactoryを設定して、そのSSLContextを使用する必要があります(例 こちら を参照)。ただし、SSLContextを直接サポートしているApache Http Client 4.xにアップグレードする価値があります。

Pascalの回答 を使用して、証明書を正しくインポートすることもできます。繰り返しになりますが、その質問に対する(Kevinによる)承認済みの回答に従うと、実際にはエラーは無視されますが、これにより接続がMITM攻撃に対して脆弱になります。

13
Bruno

HttpClient 4.3、それは簡単です、

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

それはあなたの問題を解決するはずです

2
eddy_sby2000

これが私にとってうまくいったすべてを本当に無視したい場合:

SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new TrustStrategy() {
    @Override
    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        return true;
    }
}).build();
HostnameVerifier hnv = new NoopHostnameVerifier();      
SSLConnectionSocketFactory sslcf = new SSLConnectionSocketFactory(sslContext, hnv);     
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslcf).build()
1
Kyle

証明書を無視すると、同じコードが実稼働環境に移動し、大混乱を引き起こす可能性があるため、それ自体に害があります。

以下の例はJersey Rest Clientの場合です

private static final com.Sun.jersey.api.client.Client client = com.Sun.jersey.api.client.Client.create(configureClient());
final com.Sun.jersey.api.client.WebResource webResource = client.resource("url");
try {
    com.Sun.jersey.api.client.ClientResponse response = webResource.type(MediaType.APPLICATION_JSON_TYPE)
                            .accept(MediaType.APPLICATION_JSON_TYPE)
                            .get(com.Sun.jersey.api.client.ClientResponse.class);
}catch(com.Sun.jersey.api.client.ClientHandlerException che){
    che.printStackTrace();  
}

証明書を無視すると、次のようになります。

public static ClientConfig configureClient() {
    TrustManager[ ] certs = new TrustManager[ ] {
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
            }
    };
    SSLContext ctx = null;
    try {
        ctx = SSLContext.getInstance("SSL");
        ctx.init(null, certs, new SecureRandom());
    } catch (Java.security.GeneralSecurityException ex) {
    }
    HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());

    ClientConfig config = new DefaultClientConfig();
    try {
        config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(
                new HostnameVerifier() {
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                },
                ctx
        ));
    } catch(Exception e) {
    }

    return config;
}
0
Anamika