【第一部分税课,忽略證書信任問題】 直接去第二部分性能問題
搬運自:https://blog.csdn.net/lizeyang/article/details/18983843
java程序在訪問https資源時,出現(xiàn)報錯
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
1)https通信過程
(1)客戶使用https的URL訪問Web服務器立磁,要求與Web服務器建立SSL連接。
(2)Web服務器收到客戶端請求后剥槐,會將網(wǎng)站的證書信息(證書中包含公鑰)傳送一份給客戶端唱歧。
(3)客戶端的瀏覽器與Web服務器開始協(xié)商SSL連接的安全等級,也就是信息加密的等級粒竖。
(4)客戶端的瀏覽器根據(jù)雙方同意的安全等級颅崩,建立會話密鑰,然后利用網(wǎng)站的公鑰將會話密鑰加密蕊苗,并傳送給網(wǎng)站挨摸。
(5)Web服務器利用自己的私鑰解密出會話密鑰。
(6)Web服務器利用會話密鑰加密與客戶端之間的通信岁歉。
2)java程序的證書信任規(guī)則
如上文所述,客戶端會從服務端拿到證書信息膝蜈。調(diào)用端(客戶端)會有一個證書信任列表锅移,拿到證書信息后,會判斷該證書是否可信任饱搏。
如果是用瀏覽器訪問https資源非剃,發(fā)現(xiàn)證書不可信任,一般會彈框告訴用戶推沸,對方的證書不可信任备绽,是否繼續(xù)之類券坞。
Java虛擬機并不直接使用操作系統(tǒng)的keyring,而是有自己的security manager肺素。與操作系統(tǒng)類似恨锚,jdk的security manager默認有一堆的根證書信任。如果你的https站點證書是花錢申請的倍靡,被這些根證書所信任猴伶,那使用java來訪問此https站點會非常方便。因此塌西,如果用java訪問https資源他挎,發(fā)現(xiàn)證書不可信任,則會報文章開頭說到的錯誤捡需。
解決問題的方法
1)將證書導入到jdk的信任證書中(理論上應該可行办桨,未驗證)
2)在客戶端(調(diào)用端)添加邏輯,忽略證書信任問題
第一種方法站辉,需要在每臺運行該java程序的機器上呢撞,都做導入操作,不方便部署庵寞,因此狸相,采用第二種方法。下面貼下該方法對應的代碼捐川。
1)先實現(xiàn)驗證方法
void trustAllHttpsCertificates() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[1];
trustAllCerts[0] = new MyTrustManager();
SSLContext sslCtx = SSLContext.getInstance("SSL");
sslCtx.init(null, trustAllCerts, null);
javax.net.ssl.SSLSocketFactory sslsocketfactory = sslCtx.getSocketFactory();
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sslsocketfactory);
}
class MyTrustManager implements TrustManager, X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
}
2)在訪問https資源前脓鹃,調(diào)用
try {
trustAllHttpsCertificates();
} catch (Exception e) {
e.printStackTrace();
} //setDefaultSSLSocketFactory
HostnameVerifier hv = (urlHostName, session) -> {
Log.e("apibhuc", "Warning: URL Host: v7" + urlHostName + " vs. " + session.getPeerHost());
return true;
};
HttpsURLConnection.setDefaultHostnameVerifier(hv); // outer try catch
【第二部分,以上代碼性能問題】
如果你像上面說的每次請求都添加上面的代碼古沥,那么會有性能問題瘸右,具體就是訪問耗時,應將將上面部分代碼放至應用初始化時岩齿;