Java 跳过 HTTPS 请求过程中证书验证问题

受益于谷歌和苹果对 HTTPS 的强制升级要求,服务已经全面升级了,安全性提高的同时也引起了新的问题。

由于 HTTPS 证书还是很贵的,所以各种测试环境上各种非法证书,通过浏览器访问的时候可以直接选择信任证书,但通过代码就不行了,会直接抛出证书不通过的异常:java.security.cert.CertificateException javax.net.ssl.SSLHandshakeException sun.security.validator.ValidatorException

这时候我们可以选择直接跳过验证,当然这会使 HTTPS 的安全性就失效了,所以生产环境尽量不要用。

先进行配置初始化:

private static SSLSocketFactory sslFactory;
private static HostnameVerifier nameVerifier;

static {
    try {
        SSLContext sslc = SSLContext.getInstance("TLS");
        TrustManager[] trustManagerArray = {new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        }};
        sslc.init(null, trustManagerArray, null);
        sslFactory = sslc.getSocketFactory();

        nameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                return true;
            }
        };
    } catch (Exception e) {
        log.error("系统初始化失败", e);
    }
}

一般正常的 url 链接代码可能是是这样的:

public static String get(String urlLocation) throws Exception {

    HttpURLConnection conn = null;
    InputStream is = null;
    try {
        URL url = new URL(urlLocation);
        conn = (HttpURLConnection)url.openConnection();
        conn.connect();

        is = conn.getInputStream();
        return IOUtils.toString(is, "UTF-8");
    } finally {
        IOUtils.closeQuietly(is);
        if(conn != null) conn.disconnect();
    }
}

只需要简单修改,在进行实际连接前进行网络协议判断然后进行设置就可以了:

conn = (HttpURLConnection)url.openConnection();
if(conn instanceof HttpsURLConnection) {
    HttpsURLConnection https = (HttpsURLConnection) conn;
    https.setSSLSocketFactory(sslFactory);
    https.setHostnameVerifier(nameVerifier);
}
conn.connect();

到此结束,测试通过。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注