根據確切的證書問題,您可能會收到類似以下內容之一的錯誤,盡管我幾乎肯定有其他表現形式:
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