Java 11 introduced the HTTP Client, an API that made it easier to send HTTP requests with vanilla Java.
By default, it throws an exception if there are certificate path or hostname verification errors in the request.
Let’s see how to bypass certificate validations for cases where this is really necessary.
To ignore both certificate path and hostname verifications, create an X509ExtendedTrustManager
extension that doesn't do any verification and use it to init an SSLContext
for an HttpClient
:
var trustManager = new X509ExtendedTrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) { } @Override public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) { } @Override public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) { } }; var sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom()); var client = HttpClient.newBuilder() .sslContext(sslContext) .build();
With this solution, only that client with that custom SSLContext
specified will allow insecure requests. So in many cases this is the best option.
You can use the example URLs https://expired.badssl.com/
and https://wrong.host.badssl.com/
to test:
var expiredRequest = HttpRequest.newBuilder() .uri(URI.create("https://expired.badssl.com/")) .build(); var wrongHostRequest = HttpRequest.newBuilder() .uri(URI.create("https://wrong.host.badssl.com/")) .build(); client.send(expiredRequest, BodyHandlers.discarding()); client.send(wrongHostRequest, BodyHandlers.discarding());
Without disabling verification, this error would occur for an expired SSL/TLS certificate:
javax.net.ssl.SSLHandshakeException: PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed ... Caused by: java.security.cert.CertificateExpiredException: NotAfter: Sun Apr 12 20:59:59 BRT 2015
And for a wrong hostname:
javax.net.ssl.SSLHandshakeException: No subject alternative DNS name matching wrong.host.badssl.com found. ... Caused by: java.security.cert.CertificateException: No subject alternative DNS name matching wrong.host.badssl.com found.
You can set the jdk.internal.httpclient.disableHostnameVerification
system property to "true"
to disable only hostname verification, as shown in the Javadoc.
This solution isn’t applied to certificate path verification, so an expired certificate would still cause an exception. And it has the disadvantage of disabling hostname verification for requests from all clients.
If you create an X509TrustManager
implementation (instead of an X509ExtendedTrustManager
extension) that doesn't do verifications and use it on a client, it will ignore only the certificate path verification:
var sslContext = SSLContext.getInstance("TLS"); var trustManager = new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { } }; sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom()); var client = HttpClient.newBuilder() .sslContext(sslContext) .build(); var request = HttpRequest.newBuilder() .uri(URI.create("https://expired.badssl.com/")) .build(); client.send(request, BodyHandlers.discarding());
So this solution isn’t applied to hostname verification.
To disable certificate verification, the best option in most cases is to use an X509ExtendedTrustManager
extension that doesn't do any verification, as this will bypass both certificate path and hostname verifications and will only apply to the specified client.