摘要:程序在訪問資源時(shí),出現(xiàn)報(bào)錯(cuò)這本質(zhì)上,是在訪問資源時(shí)的證書信任問題。因此,如果用訪問資源,發(fā)現(xiàn)證書不可信任,則會(huì)報(bào)文章開頭說到的錯(cuò)誤。
java程序在訪問https資源時(shí),出現(xiàn)報(bào)錯(cuò)
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
這本質(zhì)上,是java在訪問https資源時(shí)的證書信任問題。
如何解決這個(gè)問題呢?
解決這個(gè)問題前,要了解
1)https通信過程
客戶端在使用HTTPS方式與Web服務(wù)器通信時(shí)有以下幾個(gè)步驟,如圖所示。
(1)客戶使用https的URL訪問Web服務(wù)器,要求與Web服務(wù)器建立SSL連接。
(2)Web服務(wù)器收到客戶端請(qǐng)求后,會(huì)將網(wǎng)站的證書信息(證書中包含公鑰)傳送一份給客戶端。
(3)客戶端的瀏覽器與Web服務(wù)器開始協(xié)商SSL連接的安全等級(jí),也就是信息加密的等級(jí)。
(4)客戶端的瀏覽器根據(jù)雙方同意的安全等級(jí),建立會(huì)話密鑰,然后利用網(wǎng)站的公鑰將會(huì)話密鑰加密,并傳送給網(wǎng)站。
(5)Web服務(wù)器利用自己的私鑰解密出會(huì)話密鑰。
(6)Web服務(wù)器利用會(huì)話密鑰加密與客戶端之間的通信。
2)java程序的證書信任規(guī)則
如上文所述,客戶端會(huì)從服務(wù)端拿到證書信息。調(diào)用端(客戶端)會(huì)有一個(gè)證書信任列表,拿到證書信息后,會(huì)判斷該證書是否可信任。
如果是用瀏覽器訪問https資源,發(fā)現(xiàn)證書不可信任,一般會(huì)彈框告訴用戶,對(duì)方的證書不可信任,是否繼續(xù)之類。
Java虛擬機(jī)并不直接使用操作系統(tǒng)的keyring,而是有自己的security manager。與操作系統(tǒng)類似,jdk的security manager默認(rèn)有一堆的根證書信任。如果你的https站點(diǎn)證書是花錢申請(qǐng)的,被這些根證書所信任,那使用java來訪問此https站點(diǎn)會(huì)非常方便。因此,如果用java訪問https資源,發(fā)現(xiàn)證書不可信任,則會(huì)報(bào)文章開頭說到的錯(cuò)誤。
解決問題的方法
1)將證書導(dǎo)入到j(luò)dk的信任證書中(理論上應(yīng)該可行,未驗(yàn)證)
2)在客戶端(調(diào)用端)添加邏輯,忽略證書信任問題
第一種方法,需要在每臺(tái)運(yùn)行該java程序的機(jī)器上,都做導(dǎo)入操作,不方便部署,因此,采用第二種方法。下面貼下該方法對(duì)應(yīng)的代碼。
驗(yàn)證可行的代碼
1)先實(shí)現(xiàn)驗(yàn)證方法
HostnameVerifier hv = new HostnameVerifier() { public boolean verify(String urlHostName, SSLSession session) { System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost()); return true; } }; private static void trustAllHttpsCertificates() throws Exception { javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; javax.net.ssl.TrustManager tm = new miTM(); trustAllCerts[0] = tm; javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext .getInstance("SSL"); sc.init(null, trustAllCerts, null); javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc .getSocketFactory()); } static class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public boolean isServerTrusted( java.security.cert.X509Certificate[] certs) { return true; } public boolean isClientTrusted( java.security.cert.X509Certificate[] certs) { return true; } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { return; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { return; } }
2)在訪問https資源前,調(diào)用
trustAllHttpsCertificates(); HttpsURLConnection.setDefaultHostnameVerifier(hv);
以下是一個(gè)具體的例子:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; import org.apache.log4j.Logger; import org.htmlparser.util.ParserException; import com.xwtech.parser.GetRequestHtmlParser; import com.xwtech.pojo.ExtendCandidate; /* * GET請(qǐng)求類 */ public class GetRequest { private String url = "https://b2b.10086.cn/b2b/main/viewNoticeContent.html?noticeBean.id="; private Logger logger; public GetRequest() { logger = Logger.getLogger(GetRequest.class); } private static void trustAllHttpsCertificates() throws Exception { javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; javax.net.ssl.TrustManager tm = new miTM(); trustAllCerts[0] = tm; javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, null); javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } public void getData(String id) { this.url = url + id; BufferedReader in = null; HttpURLConnection conn = null; String result = ""; try { //該部分必須在獲取connection前調(diào)用 trustAllHttpsCertificates(); HostnameVerifier hv = new HostnameVerifier() { public boolean verify(String urlHostName, SSLSession session) { logger.info("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost()); return true; } }; HttpsURLConnection.setDefaultHostnameVerifier(hv); conn = (HttpURLConnection)new URL(url).openConnection(); // 發(fā)送GET請(qǐng)求必須設(shè)置如下兩行 conn.setDoInput(true); conn.setRequestMethod("GET"); // flush輸出流的緩沖 in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { logger.error("發(fā)送 GET 請(qǐng)求出現(xiàn)異常! 請(qǐng)求ID:"+id+" "+e.getMessage()+" "); } finally {// 使用finally塊來關(guān)閉輸出流、輸入流 try { if (in != null) { in.close(); } } catch (IOException ex) { logger.error("關(guān)閉數(shù)據(jù)流出錯(cuò)了! "+ex.getMessage()+" "); } } // 獲得相應(yīng)結(jié)果result,可以直接處理...... } static class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) { return true; } public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) { return true; } public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { return; } public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { return; } } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/73806.html
摘要:設(shè)置協(xié)商加密算法時(shí),優(yōu)先使用我們服務(wù)端的加密套件,而不是客戶端瀏覽器的加密套件。 nginx下配置ssl本來是很簡(jiǎn)單的,無論是去認(rèn)證中心買SSL安全證書還是自簽署證書,但最近公司OA的一個(gè)需求,得以有個(gè)機(jī)會(huì)實(shí)際折騰一番。一開始采用的是全站加密,所有訪問http:80的請(qǐng)求強(qiáng)制轉(zhuǎn)換(rewrite)到https,后來自動(dòng)化測(cè)試結(jié)果說響應(yīng)速度太慢,https比http慢慢30倍,心想怎么可...
摘要:順便一提,如果要使用客戶端認(rèn)證就必須使用服務(wù)端認(rèn)證。修改,添加如下可以看到我們開啟了客戶端認(rèn)證,也開啟了服務(wù)端認(rèn)證。所以如果要正確訪問得像下面這樣,指定證書,以及客戶端自己簽發(fā)的證書及測(cè)試我們現(xiàn)在用來訪問看看。 常見的https網(wǎng)站做的是服務(wù)端認(rèn)證(server authentication),瀏覽器通過證書判斷你所訪問的https://baidu.com是否真的是百度,而不是其他人偽...
摘要:簡(jiǎn)介移動(dòng)端調(diào)試一直都是一個(gè)痛點(diǎn),因?yàn)橐苿?dòng)終端對(duì)于我們來說是一個(gè)黑盒,它無法像端一樣,我們可以通過很方便的調(diào)出開發(fā)者工具。如果沒有調(diào)試工具這種情況下我們就很難定位問題,接下來的主題就是介紹如何使用進(jìn)行移動(dòng)端調(diào)試。 簡(jiǎn)介 ? 移動(dòng)端調(diào)試一直都是一個(gè)痛點(diǎn),因?yàn)橐苿?dòng)終端對(duì)于我們來說是一個(gè)黑盒,它無法像PC端一樣,我們可以通過F12很方便的調(diào)出開發(fā)者工具。在開發(fā)中經(jīng)常會(huì)遇到同樣一份...
閱讀 3109·2021-02-22 17:12
閱讀 732·2019-08-30 15:55
閱讀 3114·2019-08-30 15:54
閱讀 1401·2019-08-29 16:56
閱讀 1872·2019-08-29 15:13
閱讀 1733·2019-08-29 13:19
閱讀 612·2019-08-26 13:40
閱讀 2833·2019-08-26 10:26