HTTPS通信的具體原理,這里不做介紹。作為一個(gè)C/S的通信協(xié)議,HTTPS是分為Client和Server的,這里會(huì)介紹當(dāng)Tomcat WEB Server分別作為HTTPS的客戶端和服務(wù)器端時(shí)候的配置和實(shí)現(xiàn)。
WEB容器作為HTTPS的服務(wù)器端
Tomcat提供HTTPS Server的功能和瀏覽器等其他HTTPS客戶端進(jìn)行交互是很常見的使用方式。Tomcat配置實(shí)現(xiàn)了HTTPS Server之后,瀏覽器就可以通過https協(xié)議訪問Tomcat提供的WEB服務(wù)了。
具體配置步驟如下:
生成證書
可以用java自動(dòng)的工具生成證書,如果已經(jīng)有可信的第三方簽發(fā)的證書或者其他工具生成的服務(wù)器證書,此步驟可以忽略,直接進(jìn)行后面的步驟。
服務(wù)器證書用于后續(xù)發(fā)生SSL協(xié)商時(shí),發(fā)給SSL Client用來驗(yàn)證服務(wù)器的。在HTTPS應(yīng)用場(chǎng)景中,默認(rèn)SSL Client一般是瀏覽器,因?yàn)闉g覽器出廠的時(shí)候會(huì)內(nèi)置一些可信的第三方CA作為驗(yàn)證的CA鏈。所以此處如果使用了這些第三方CA簽發(fā)的證書作為服務(wù)器的證書,則瀏覽器不用做任何設(shè)置就可以對(duì)服務(wù)器端進(jìn)行有效的驗(yàn)證。否則,因?yàn)轵?yàn)證證書需要一直到Root CA建立信任關(guān)系鏈,這里對(duì)于自己生成的證書有兩種處理的方式:
- 在本地建立CA,簽發(fā)服務(wù)器證書給Tomcat使用,將本地CA證書鏈導(dǎo)入瀏覽器作為可信的CA,后續(xù)用來在瀏覽器端驗(yàn)證Tomcat的服務(wù)器證書。
- Tomcat的瀏覽器證書使用自簽名證書,這樣客戶端就不用再做任何配置了。
上述兩種方式在WEB開發(fā)的測(cè)試過程中使用都是沒有問題,一般用第二種方法,更簡(jiǎn)潔一些。但是在實(shí)際的生產(chǎn)環(huán)境,是行不通的。
- 方法一:因?yàn)閃EB服務(wù)面向的訪問群體不確定,我們沒有辦法將自己生成的CA證書鏈導(dǎo)入到所有的瀏覽器中。
- 方法二:自簽名證書可以協(xié)商安全的SSL通道,保證HTTP通信的通道安全,但是因?yàn)槭亲院灻?,客戶端無法確認(rèn)服務(wù)器端的身份,無法阻止基于中間人的釣魚攻擊。所以最好的方式還是使用可信的第三方簽發(fā)的證書,當(dāng)然這種服務(wù)是收費(fèi)的。
我們下面只說明一下測(cè)試環(huán)境中證書的使用,這里使用自簽名證書做示例:
生成證書

這里使用了網(wǎng)上的圖片做說明,大致步驟是相同的,注意,這里的common-name,也就是名字和姓氏那一欄需要和WEB域名一致。在實(shí)際應(yīng)用過程中,瀏覽器判斷WEB Server的身份是否可行的通用做法是比較證書字段中的common-name和WEB的域名是否相同,如果不相同會(huì)提示W(wǎng)EB Server不可信。
導(dǎo)出證書

上一步中只是在keystore中生成了一個(gè)證書,這個(gè)keystore中可以有很多證書,這里我們把需要的證書文件導(dǎo)出,導(dǎo)出的時(shí)候請(qǐng)指定別名。記下導(dǎo)出的證書的路徑,后面需要用到。
至此,證書的操作就已經(jīng)完成了。
配置Tomcat服務(wù)器
Tomcat服務(wù)器默認(rèn)提供了HTTP服務(wù),如果需要用HTTPS服務(wù),需要打開相應(yīng)的端口,和做一些必要的配置。

如上圖所示,protocol中使用的是coyote方式,如果是其他的方式,如APR方式,可能配置方法會(huì)不同,具體的如果有需求,可以到網(wǎng)上搜索相關(guān)資料。
注意:這里keystoreFile選擇當(dāng)時(shí)生成的證書庫(kù),keystorePass填寫自己的密碼即可。
使用HTTPS服務(wù)登錄
將配置好的tomcat服務(wù)器重啟之后,會(huì)自動(dòng)加載證書庫(kù)中的證書,根據(jù)請(qǐng)求的域名發(fā)
送相關(guān)的證書。如圖:

這里因?yàn)橛玫氖亲院灻C書,所以提示是無效的證書認(rèn)證,我們可以選擇繼續(xù)訪問,可以正常進(jìn)入首頁(yè)。
WEB容器作為HTTPS的客戶端
Tomcat因?yàn)槭荳EB服務(wù)的提供者,所以作為HTTPS的服務(wù)器端是很好理解的。但是在實(shí)際應(yīng)用中WEB服務(wù)器也是很有可能作為HTTPS的客戶端的。解決跨域訪問就是一個(gè)這樣的應(yīng)用場(chǎng)景。考慮下面的情況:
在www.A.com的網(wǎng)站中,需要獲取www.B.com中的某一個(gè)資源,正常的想法是,通過B提供的API直接在A的頁(yè)面中發(fā)送HTTP Get/Post請(qǐng)求到B的服務(wù)器中獲取,這樣是否可以呢?實(shí)際是不行的,因?yàn)闉g覽器有同源策略,是會(huì)默認(rèn)禁止在一個(gè)域中向另外一個(gè)域中直接發(fā)起請(qǐng)求的,如果這樣做了,會(huì)出現(xiàn)一個(gè)access-control-allow-origin的錯(cuò)誤,這里不仔細(xì)介紹,如果有興趣的可以搜索一下相關(guān)的內(nèi)容。
我們可以看到,在瀏覽器中,直接在A的頁(yè)面中獲取B的資源是不可行的,但是實(shí)際上我們又確實(shí)有這樣的需求,怎么辦呢?可以通過A的后臺(tái)做代理去B獲取資源,然后再將獲取的資源返回給A。這時(shí)候WEB 服務(wù)器(tomcat)就有可能作為HTTPS的客戶端了。
準(zhǔn)備證書
在HTTPS的使用場(chǎng)景中,一般只會(huì)要求對(duì)服務(wù)器進(jìn)行認(rèn)證,目前不會(huì)也不太可能對(duì)客戶端進(jìn)行認(rèn)證。所以,作為HTTPS Client的時(shí)候,本身是不需要有證明自己身份的證書的。但是因?yàn)橐?yàn)證服務(wù)器,所以需要有可信任的證書鏈。尋找可信任的證書鏈的具體的原則如下:
客戶端的TrustStore文件中保存著被客戶端所信任的服務(wù)器的證書信息??蛻舳嗽谶M(jìn)行SSL連接時(shí),JSSE將根據(jù)這個(gè)文件中的證書決定是否信任服務(wù)器端的證書。在SunJSSE中,有一個(gè)信任管理器類負(fù)責(zé)決定是否信任遠(yuǎn)端的證書,這個(gè)類有如下的處理規(guī)則:
- 若系統(tǒng)屬性javax.net.sll.trustStore指定了TrustStore文件,那么信任管理器就去jre安裝路徑下的lib/security/目錄中尋找并使用這個(gè)文件來檢查證書。
- 若該系統(tǒng)屬性沒有指定TrustStore文件,它就會(huì)去jre安裝路徑下尋找默認(rèn)的TrustStore文件,這個(gè)文件的相對(duì)路徑為:lib/security/jssecacerts。
- 若jssecacerts不存在,但是cacerts存在(它隨J2SDK一起發(fā)行,含有數(shù)量有限的可信任的基本證書),那么這個(gè)默認(rèn)的TrustStore文件就是lib/security/cacerts。
所以我們?cè)趯?shí)際使用中,要看看具體證書放在哪里,java1.8中,證書是放在lib/security/cacerts中的。這里就包含了默認(rèn)的一些第三方證書機(jī)構(gòu)的可信的CA證書鏈。只要我們要連接的HTTPS服務(wù)器端的證書是這些第三方證書機(jī)構(gòu)頒發(fā)的,則不需要做任何處理。如果服務(wù)器端沒有使用自己的CA簽發(fā)的證書或者自簽名證書怎么辦呢?有兩個(gè)解決辦法:
- 按照以上信任管理器的規(guī)則,將服務(wù)端的公鑰導(dǎo)入到j(luò)ssecacerts,或者是在系統(tǒng)屬性中設(shè)置要加載的trustStore文件的路徑;證書導(dǎo)入可以用如下命令:keytool -import -file src_cer_file –keystore dest_cer_store;至于證書可以通過瀏覽器導(dǎo)出獲得;
- 實(shí)現(xiàn)自己的證書信任管理器類,比如MyX509TrustManager,該類必須實(shí)現(xiàn)X509TrustManager接口中的三個(gè)method;然后在HttpsURLConnection中加載自定義的類。
第一種方法稍嫌繁瑣,第二種方法可能會(huì)更方便一些,但是有可能導(dǎo)致安全問題。因?yàn)槲覀冞@里主要是和阿里的HTTPS服務(wù)器連接,阿里用的是可信第三方CA頒發(fā)的證書,所以不存在上述說的證書無法驗(yàn)證的問題。
至此,證書已經(jīng)準(zhǔn)備好了,可以進(jìn)行編碼驗(yàn)證了。
連接HTTPS服務(wù)器端
這部分工作比較簡(jiǎn)單,在Java中要訪問Https鏈接時(shí),會(huì)用到一個(gè)關(guān)鍵類HttpsURLConnection, 參見如下實(shí)現(xiàn)代碼:

創(chuàng)建一個(gè)URL的實(shí)例,然后打開鏈接,就可以進(jìn)行一次Request操作了,通過InputStreamReader類可以獲取返回的信息。實(shí)際測(cè)試過,可以從阿里的認(rèn)證服務(wù)器獲取回應(yīng)信息。具體的請(qǐng)求的參數(shù)和返回?cái)?shù)據(jù)的處理可以在實(shí)際的操作過程中進(jìn)行完善。