Игнорировать ошибки сертификата SSL с Java
Apache Http Client. Вы можете увидеть соответствующий код здесь:
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-сертификатов (только установив его для подготовки, он не будет использоваться в рабочей среде). Тем не менее, я все еще получаю следующее исключение /stacktrace:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building unable to find valid certification path to requested target
Любые советы будут великолепны. Если я делаю TrustManager неправильно, или если я должен выполнять метод HTTP Post по-другому, в любом случае.
Спасибо!
4 ответа
Во-первых, не игнорируйте ошибки сертификата. Разберись с ними. Игнорирование ошибок сертификата открывает соединение с потенциальными атаками MITM. Это похоже на выключение зуммера в дымовой сигнализации, потому что иногда он издает шум...
Конечно, заманчиво сказать, что это только для тестового кода, он не попадет в производство, но мы все знаем, что происходит, когда приближается крайний срок: код не показывает никаких ошибок при тестировании -> мы можем отправить его как есть. Вы должны настроить тестовый CA вместо этого, если вам нужно. Это не очень сложно сделать, и весь процесс, безусловно, не сложнее, чем введение собственного кода для разработки и удаление его в производство.
Вы явно используете Apache Http Client:
HttpClient client = new HttpClient();
int statusCode = client.executeMethod(method);
Тем не менее, вы инициализируете javax.net.ssl.HttpsURLConnection
с SSLContext
вы создали:
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
Это полностью не зависит от настроек Apache Http Client.
Вместо этого вы должны настроить SSLContext
для клиентской библиотеки Apache Http, как описано в этом ответе. Если вы используете Apache Http Client 3.x, вам нужно настроить свой собственный SecureProtocolSocketFactory
использовать это SSLContext
(см. примеры здесь). Хотя стоит обновить Apache Http Client 4.x, который имеет прямую поддержку SSLContext
,
Вы также можете использовать ответ Паскаля, чтобы правильно импортировать сертификат. Опять же, если вы будете следовать принятому ответу (Кевину) на этот вопрос, вы действительно проигнорируете ошибку, но это сделает соединение уязвимым для атак MITM.
Если вы действительно хотите игнорировать все, что у меня сработало:
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()
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();
это должно решить твою проблему
Игнорирование сертификатов приносит свой вред, потому что один и тот же код может перемещаться в производственной среде и может привести к хаосу.
Ниже приведен пример с клиентом отдыха Джерси
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;
}