在Java客户端中接受服务器的自签名SSL证书
这看起来像一个标准的问题,但我无法在任何地方find明确的方向。
我有Java代码尝试连接到可能自签名(或过期)证书的服务器。 该代码报告以下错误:
[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught when processing request: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
据我了解,我必须使用keytool,并告诉java,这是可以的,以允许此连接。
解决这个问题的所有指令都假设我完全熟悉keytool,比如
为服务器生成私钥并将其导入到密钥库中
有没有人可以发布详细的说明?
我正在运行Unix,所以bash脚本将是最好的。
不知道是否重要,但代码在jboss中执行。
基本上有两种select:将自签名证书添加到您的JVM信任库或configuration您的客户端
选项1
从浏览器导出证书并将其导入到JVM信任库(以build立信任链):
<JAVA_HOME>\bin\keytool -import -v -trustcacerts -alias server-alias -file server.cer -keystore cacerts.jks -keypass changeit -storepass changeit
选项2
禁用证书validation(来自Example Depot的代码):
// Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (GeneralSecurityException e) { } // Now you can access an https URL without having the certificate in the truststore try { URL url = new URL("https://hostname/index.html"); } catch (MalformedURLException e) { }
请注意, 我不build议使用选项2 。 禁用信任pipe理器会破坏SSL的某些部分,使您在中间人攻击时容易受到攻击。 更喜欢选项#1,或者甚至更好的是让服务器使用由公知的CA签署的“真实”证书。
我将这个问题JDK 8u74
不属于默认JVM可信主机的证书提供者。 提供商是www.identrust.com ,但那不是我想要连接的域名。 该域名已从该提供商获得其证书。 请参阅JDK / JRE中的默认列表是否将跨root用户信任信任? – 读几个条目。 另请参阅支持哪些浏览器和操作系统让我们encryption 。
所以,为了连接到我感兴趣的域名,其中有一个从identrust.com
发布的证书我做了以下步骤。 基本上,我必须获得JVM信任的identrust.com( DST Root CA X3
)证书。 我能够这样做,使用Apache HttpComponents 4.5像这样:
1:通过证书链下载说明获取不诚信证书 。 点击DST根CA X3链接。
2:将该string保存到名为“DST根CA X3.pem”的文件中。 请务必在文件开头和结尾添加“—– BEGIN CERTIFICATE —–”和“—– END CERTIFICATE —–”行。
3:使用以下命令创build一个java密钥库文件cacerts.jks:
keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword
4:将生成的cacerts.jks密钥库复制到java /(maven)应用程序的资源目录中。
5:使用下面的代码来加载这个文件并将其附加到Apache 4.5 HttpClient。 这将解决所有具有从indetrust.com
颁发的证书的域的问题indetrust.com
oracle将证书包含到JRE默认密钥库中。
SSLContext sslcontext = SSLContexts.custom() .loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(), new TrustSelfSignedStrategy()) .build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()); CloseableHttpClient httpclient = HttpClients.custom() .setSSLSocketFactory(sslsf) .build();
当构build项目时,cacerts.jks将被复制到类path中并从那里加载。 我没有,在这个时间点,testing对其他ssl网站,但如果上述代码“链”在这个证书,那么他们也会工作,但我不知道。
参考: 自定义SSL上下文以及如何使用Java HttpsURLConnection接受自签名证书?
而不是设置默认的套接字工厂(IMO是一件坏事),而是会影响当前的连接,而不是你试图打开的每一个SSL连接:
URLConnection connection = url.openConnection(); // JMD - this is a better way to do it that doesn't override the default SSL factory. if (connection instanceof HttpsURLConnection) { HttpsURLConnection conHttps = (HttpsURLConnection) connection; // Set up a Trust all manager TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }; // Get a new SSL context SSLContext sc = SSLContext.getInstance("TLSv1.2"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); // Set our connection to use this SSL context, with the "Trust all" manager in place. conHttps.setSSLSocketFactory(sc.getSocketFactory()); // Also force it to trust all hosts HostnameVerifier allHostsValid = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; // and set the hostname verifier. conHttps.setHostnameVerifier(allHostsValid); } InputStream stream = connection.getInputStream();
信任所有SSL证书: – 如果要在testing服务器上进行testing,则可以绕过SSL。 但不要使用此代码进行生产。
public static class NukeSSLCerts { protected static final String TAG = "NukeSSLCerts"; public static void nuke() { try { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { X509Certificate[] myTrustedAnchors = new X509Certificate[0]; return myTrustedAnchors; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) {} @Override public void checkServerTrusted(X509Certificate[] certs, String authType) {} } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { return true; } }); } catch (Exception e) { } }
}
请在Activity或应用程序类中的onCreate()函数中调用该函数。
NukeSSLCerts.nuke();
这可以在Android中使用Volley。
Apache HttpClient 4.5支持接受自签名证书:
SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(new TrustSelfSignedStrategy()) .build(); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext); Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create() .register("https", socketFactory) .build(); HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg); CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(cm) .build(); HttpGet httpGet = new HttpGet(url); CloseableHttpResponse sslResponse = httpClient.execute(httpGet);
这将构build一个SSL套接字工厂,该工厂将使用TrustSelfSignedStrategy
,将其注册到自定义连接pipe理器,然后使用该连接pipe理器进行HTTP GET。
我赞同那些吟唱“不做生产”的人,但是有用例来接受生产以外的自签证书; 我们在自动化集成testing中使用它们,以便我们使用SSL(就像在生产中一样),即使没有在生产硬件上运行。
如果“他们”正在使用自签名证书,则需要他们采取必要步骤使其服务器可用。 具体来说,这意味着以可靠的方式离线向您提供证书。 所以让他们这样做。 然后使用“JSSE参考指南”中所述的keytool将其导入到信任库中。 甚至不要考虑在这里发布的不安全的TrustManager。
编辑为了十七 (!)downvoters和下面的许多评论者的利益,谁显然还没有真正阅读我在这里写了什么,这不是一个反对自我签名证书jeremiad。 正确实施自签证书没有任何问题。 但是,实施它们的正确方法是通过脱机过程安全地传递证书,而不是通过未经身份validation的渠道进行身份validation。 这当然是显而易见的? 对于我曾经工作过的每一个有安全意识的组织,从拥有数千家分支机构的银行到我自己的公司,都是显而易见的。 信任所有证书的客户端代码库“解决scheme”,其中包括绝对任何人签署的自签名证书,或任何将自己设置为CA的任意仲裁机构,其本身并不安全。 这只是在安全地玩。 这是毫无意义的。 你有一个私人的,防篡改,答复certificate,注射certificate与…有人交谈。 任何人。 一个男人在中间。 模仿者 任何人。 你可能只是使用明文。