How to disable certificate validations in the Java HTTP Client

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.

Disabling all certificate verifications for a specific client

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());

Errors you would get

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.

Disabling hostname verification by system property

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.

Disabling only certificate path verification

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.

Conclusion

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.

  • 28
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值