根据确切的证书问题,您可能会收到类似以下内容之一的错误,尽管我几乎肯定有其他表现形式:
java.security.cert.CertificateException: Untrusted Server Certificate Chainjavax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
要解决此问题,通常需要修改JDK信任库文件,这可能会很痛苦,而且常常会遇到麻烦。 最重要的是,您团队中的每个开发人员都必须做同样的事情,并且您在每个新环境中都会遇到相同的问题。
幸运的是,有一种方法可以以通用的方式解决问题,而不会给开发人员带来任何负担。 我们将重点介绍普通的HttpURLConnection类型的连接,因为它是最通用的类型,仍应帮助您了解其他库的使用方向。 如果您使用的是Apache HttpClient,请参见此处 。
警告:知道您在做什么!
请注意使用此代码的含义:这意味着您完全不关心主机验证,而仅使用SSL来加密通信。 您不是要防止中间人攻击,也不是要确保您已连接到您认为是的主机。 通常可以归结为一些有效的情况:
- 您在锁定的LAN环境中操作。 您不容易受到攻击者拦截的请求(或者如果存在,则问题更大)。
- 您所处的测试或开发环境中,确保通信安全并不重要。
如果这符合您的需求,请继续进行。 否则,也许要三思而后行地想要完成什么。
解决方案:修改信任管理器
既然我们已经放弃了这个免责声明,我们就可以解决眼前的实际问题。 Java允许我们控制负责验证HttpsURLConnection的主机和证书的对象。 这可以在全球范围内完成,但是我敢肯定,有经验的人会畏缩于做出如此彻底的改变的想法。 幸运的是,我们还可以根据每个请求进行操作,并且由于很难在网络上找到此类示例,因此我在下面提供了代码。 这种方法很好,因为您无需在全球范围内换掉SSLSocketFactory实现。
随时获取它并在您的项目中使用它。
package com.mycompany.http;import java.net.*;
import javax.net.ssl.*;
import java.security.*;
import java.security.cert.*;public class TrustModifier {private static final TrustingHostnameVerifierTRUSTING_HOSTNAME_VERIFIER = new TrustingHostnameVerifier();private static SSLSocketFactory factory;/** Call this with any HttpURLConnection, and it willmodify the trust settings if it is an HTTPS connection. */public static void relaxHostChecking(HttpURLConnection conn)throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {if (conn instanceof HttpsURLConnection) {HttpsURLConnection httpsConnection = (HttpsURLConnection) conn;SSLSocketFactory factory = prepFactory(httpsConnection);httpsConnection.setSSLSocketFactory(factory);httpsConnection.setHostnameVerifier(TRUSTING_HOSTNAME_VERIFIER);}}static synchronized SSLSocketFactoryprepFactory(HttpsURLConnection httpsConnection)throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {if (factory == null) {SSLContext ctx = SSLContext.getInstance("TLS");ctx.init(null, new TrustManager[]{ new AlwaysTrustManager() }, null);factory = ctx.getSocketFactory();}return factory;}private static final class TrustingHostnameVerifier implements HostnameVerifier {public boolean verify(String hostname, SSLSession session) {return true;}}private static class AlwaysTrustManager implements X509TrustManager {public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }public X509Certificate[] getAcceptedIssuers() { return null; }}}
用法
要使用上面的代码,只需在打开流之前调用RelaxHostChecking()方法即可:
URL someUrl = ... // may be HTTPS or HTTP
HttpURLConnection connection = (HttpURLConnection) someUrl.openConnection();
TrustModifier.relaxHostChecking(connection); // here's where the magic happens// Now do your work!
// This connection will now live happily with expired or self-signed certificates
connection.setDoOutput(true);
OutputStream out = connection.getOutputStream();
...
在那里,它是支持自签名证书的本地化方法的完整示例。 这不会影响您的应用程序的其余部分,而其余部分将继续具有严格的托管检查语义。 该示例可以扩展为使用配置设置来确定是否应使用宽松的主机检查,如果使用此代码主要是通过自签名证书进行开发的一种方式,我建议您这样做。
参考: Carfey Software Blog上的 JCG合作伙伴 忽略了Java中的自签名证书 。
- 使用Spring Security 3.1保护RESTful Web服务
- 使用Spring Security保护GWT应用程序
- JBoss 4.2.x Spring 3 JPA Hibernate教程
- 调试生产服务器– Eclipse和JBoss展示
- Java EE6 CDI,命名组件和限定符
- Java教程和Android教程列表
翻译自: https://www.javacodegeeks.com/2011/12/ignoring-self-signed-certificates-in.html