受益于谷歌和苹果对 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();
到此结束,测试通过。