JAVA中HTTPS那些事兒

本章是HTTPS那些事兒的第二篇文章,其他相關(guān)文章請參見:前言
本篇主要描述JAVA中與HTTPS相關(guān)的概念與代碼實(shí)現(xiàn)。

  • JAVA中的證書
  • KeyStore和TrustStore
  • SSL層證書校驗(yàn)過程
  • HttpsURLConnection

* 注意

本文純手工打造,轉(zhuǎn)載請注明出處。

JAVA中的證書

Java在JRE的安裝目錄中保存了一份默認(rèn)可信的證書列表,這個(gè)列表保存在$JRE/lib/security/cacerts文件中,可以通過JRE自帶的keytool工具打開該文件,默認(rèn)密碼為changeit??梢酝ㄟ^如下命令列出cacerts中的所有內(nèi)容:

keytool -list -keystore cacerts

回車后可以看到如下內(nèi)容:


cacerts內(nèi)容

這里顯示的是簡略內(nèi)容,如果需要查看RFC格式的輸出,可以添加rfc參數(shù),也就是:

keytool -list -rfc -keystore cacerts

還可以查看確定某一項(xiàng)的的詳細(xì)信息,只需要加上-alias-v參數(shù)即可。

KeyStore和TrustStore

我們所說的cacert文件其實(shí)是一個(gè)KeyStore文件,KeyStore文件可以存放數(shù)字證書、對稱密鑰等信息,這里所述的KeyStore只是一種文件格式。
java中的KeyStore這種文件可以分為兩類:KeyStore和TrustStore。KeyStore保存私鑰,在加解密、簽名時(shí)使用。TrustStore保存可信任的證書,用于對被訪問者進(jìn)行認(rèn)證。所以準(zhǔn)確的來說cacerts文件其實(shí)應(yīng)該屬于TrustStore
對應(yīng)于KeyStore和TrustStore,Java中有兩個(gè)類:KeyManager 和 TrustManager。在JSSE 的參考手冊中有一張示意圖,說明了java中https實(shí)現(xiàn)的各個(gè)類之間的關(guān)系:

java中SSL層類圖

可以看出如果要進(jìn)行 SSL 會話,必須得新建一個(gè) SSLSocket 對象,而 SSLSocket 對象是通過 SSLSocketFactory 來管理的,SSLSocketFactory 對象則依賴于 SSLContext ,SSLContext 對象又依賴于 keyManager、TrustManager 和 SecureRandom。而這里面的TrustManager就是負(fù)責(zé)對網(wǎng)站進(jìn)行認(rèn)證,校驗(yàn)其CA證書是否合法的。

SSL/TSL層證書校驗(yàn)過程

知道了JAVA中的https相關(guān)的類之后,我們就可以來分析JAVA中的https認(rèn)證過程了,https的認(rèn)證過程其實(shí)就是SSL/TSL的認(rèn)證過程。
1. 初始化階段
初始化SSLContext時(shí)會將TrustStore中的所有證書加載進(jìn)來。TrustManagerFactoryImpl.getCacertsKeyStore()方法負(fù)責(zé)加載證書,首先查找$JRE/lib/security/jssecacerts文件是否存在,如果不存在則加載$JRE/lib/security/cacerts文件。如果都不存在,則使用空的TrustStore,這樣的話不會有服務(wù)器的CA證書被校驗(yàn)通過。
2. 創(chuàng)建TrustManage
在TrustStore加載完畢后,會初始化TrustManager,默認(rèn)使用實(shí)現(xiàn)類X509TrustManagerImpl。該類在構(gòu)造方法中會調(diào)用KeyStores.getTrustedCerts(KeyStore)方法將TrustStore中的證書加載成X509Certificate證書。
3. checkServerTrusted
初始化后,客戶端會與服務(wù)器端建立連接,然后進(jìn)入Handshake過程,當(dāng)拿到服務(wù)器端的CA證書時(shí),會調(diào)用X509TrustManager. checkServerTrusted(…)方法,該方法完成實(shí)際的證書校驗(yàn):
a).校驗(yàn)域名/IP
校驗(yàn)訪問地址中的域名/IP(要么域名,要么IP)是否與服務(wù)器證書包含的一致,使用到HostnameChecker. match方法進(jìn)行。如果訪問使用的是域名,但服務(wù)器CA證書中沒有包含域名,則拋出錯(cuò)誤:

No subject alternative DNS name matching localhost found //其中l(wèi)ocalhost表示域名。

如果訪問使用的是IP,但服務(wù)器CA證書中沒有IP,則拋出錯(cuò)誤:

No subject alternative names present

如果域名不匹配拋出錯(cuò)誤:

No name matching localhost found //其中l(wèi)ocalhost表示域名。

如果IP不匹配,則拋出錯(cuò)誤:

No subject alternative names matching IP address 127.0.0.1 found //其中127.0.0.1表示ip。

b). 服務(wù)器證書是否可信
通過加載的TrustStore證書來校驗(yàn)服務(wù)器的證書是否由信任的證書機(jī)構(gòu)頒發(fā),使用到方法PKIXValidator.engineValidate()。該校驗(yàn)過程如果失敗,則拋出類似如下錯(cuò)誤:

PKIX path building failed: 
        sun.security.provider.certpath.SunCertPathBuilderException: 
            unable to find valid certification path to requested target

HttpsUrlConnection

java中訪問HTTP服務(wù)時(shí),會使用到HttpURLConnection,而如果訪問的是HTTPS則會使用HttpsURLConnection。相關(guān)類圖如下:

Http相關(guān)類圖

可以看出如果訪問的是Http,則使用HttpURLConnection,該類使用HttpClient完成實(shí)際的網(wǎng)絡(luò)請求。如果訪問的是HTTPS,則會使用HttpsURLConnection,同樣會使用對應(yīng)的HttpsClient。HttpsURLConnection的實(shí)現(xiàn)類HttpsURLConnectionImpl中會使用到兩個(gè)類,HostnameVerifier和SSLSocketFactory。這兩個(gè)類是實(shí)現(xiàn)HTTPS請求的核心,通過配置這兩個(gè)類可以影響SSL層校驗(yàn)域名/IP和服務(wù)器證書校驗(yàn)的過程??梢酝ㄟ^HttpsURLConnection.SetDefaultSSLSocketFactory和HttpsURLConnection.SetDefaultHostnameVerifier來設(shè)置,后續(xù)會有代碼示例。

HostnameVerifier

根據(jù)上一小節(jié)SSL/TSL層證書校驗(yàn)過程所述,在SSL/TLS層面已經(jīng)會校驗(yàn)hostname了,而在HTTPS層我們同樣有HostnameVerifier來校驗(yàn)hostname,為什么呢?其實(shí)二者之間是合作關(guān)系,HTTPS層的會影響SSL/TLS層的邏輯,他們的關(guān)系可以通過如下表格來表示:

HTTPS與SSL層Hostname校驗(yàn)器關(guān)系

  • EIA algorithm表示SSL/TLS層面的校驗(yàn),SSL層面可以通過如下方法進(jìn)行設(shè)置:
SSLParameters.setEndpointIdentificationAlgorithm(String)

可設(shè)置三個(gè)值null,HTTPS和LDAP/其他。

  • HNV表示HTTPS層面的HostnameVerifier,HNV可以通過方法HttpsURLConnection.setDefaultHostnameVerifier(obj)進(jìn)行設(shè)置,如果不設(shè)置則表中的值為defualt,如果設(shè)置了,則值為non-default。defualt的實(shí)現(xiàn)類為DefaultHostnameVerifier,該類為HttpsURLConnectionImpl的靜態(tài)內(nèi)部類。
    case1: default HNV and EIA is null
    結(jié)果是設(shè)置SSL/TSL層為HTTPS,僅由SSL/TLS層進(jìn)行hostname校驗(yàn)(JDK中默認(rèn)使用的是該規(guī)則)。
    case 2: default HNV and EIA is HTTPS
    結(jié)果是使用SSL/TSL層的值HTTPS,僅由SSL/TLS層進(jìn)行hostname校驗(yàn)
    case 3: default HNV and EIA不是HTTPS
    結(jié)果是SSL/TLS層使用設(shè)置的值LDAP/其他進(jìn)行校驗(yàn),而hostname則在HTTPS層使用默認(rèn)的DefaultHostnameVerifier校驗(yàn)
    case 4: non-default HNV and EIA is null
    SSL/TLS層不做任何校驗(yàn),HTTPS層使用設(shè)置的HNV規(guī)則校驗(yàn)hostname
    case 5: non-default HNV and EIA is HTTPS
    結(jié)果是使用EIA algorithm的值,由SSL/TLS層進(jìn)行hostname校驗(yàn)。該情況下不允許在HTTP層進(jìn)行校驗(yàn)。
    case 6: non-default HNV and EIA不是HTTPS
    結(jié)果是SSL/TLS層使用設(shè)置的值LDAP/其他進(jìn)行校驗(yàn),而hostname則在HTTPS層使用設(shè)置的HNV規(guī)則校驗(yàn)hostname

SSLSocketFactory

SSLSocketFactory是負(fù)責(zé)SSL層面校驗(yàn)hostname、客戶端證書和服務(wù)器證書的SSLSocket的工廠,默認(rèn)情況下HttpsURLConnectionImpl中會獲取默認(rèn)的SSLSockectFactory,默認(rèn)的factory會使用X509TrustManagerImpl來執(zhí)行hostname和證書的校驗(yàn),校驗(yàn)規(guī)則參考前一小節(jié)SSL/TSL層證書校驗(yàn)過程。

總結(jié)

本篇從java中TrustStore和KeyStore入手,深入到JAVA中的SSL和HTTPS相關(guān)實(shí)現(xiàn)類。分析了,java中比較核心的幾個(gè)類。后續(xù)文章,會介紹java中使用HTTPS經(jīng)常遇到的場景:不校驗(yàn)服務(wù)器證書。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容