当使用自签名证书时,Java 连接服务器时会报证书错误。在某些场景,例如测试时,又不能选择忽略证书。此时需要将自签名证书导入证书库。
Java 证书问题
当证书不被信任的时候,Java 访问 HTTPS 网站会返回:sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
在 windows 环境下,可以用浏览器打开网站并导出证书。在 linux 下可以用 openssl 工具导出证书,注意将 {HOST} 替换为真实的域名或 ip :openssl s_client -connect {HOST}:443 -showcerts </dev/null 2>/dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.cert
可以查看下证书信息:openssl x509 -in mycert.cert -text
其中比较重要的是 CN 信息,即 Common Name,如果实际请求的域名和这个证书的 CN 信息不匹配,则会校验失败,其中 {HOST} 是你请求的域名,而 {CERTED_HOST} 是证书中的域名:
Hostname {HOST} not verified:
certificate: sha1/MbFpSamF8kHCfea59drOuEXAMPLE
DN: EMAILADDRESS=test, CN={CERTED_HOST}, OU=test, O=tc, , C=ChST=Guang
subjectAltNames: []
将证书加入到 jre 的证书库中。首先获取 jre 的路径信息:
# which java
/usr/java/jdk1.8.0_51/bin/java
导入证书:keytool -import -trustcacerts -keystore /usr/java/jdk1.8.0_51/jre/lib/security/cacerts -storepass changeit -noprompt -alias mycert -file mycert.cert
如果有问题,无法重复导入同一个证书,需要删除:keytool -delete -keystore /usr/java/jdk1.8.0_51/jre/lib/security/cacerts -storepass changeit -alias mycert
忽略证书
除非是测试目的,否则不建议如此处理,容易导致中间人攻击。网上流传可以设置启动参数-Dcom.sun.net.ssl.checkRevocation=false
,实测并无作用。
如果使用的是HttpsURLConnection
,可以考虑在请求调用前一次性设置忽略所有证书校验:
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
License: (CC 3.0) BY-NC-SA