超文本傳輸安全協(xié)議(HTTPS
,常稱為 HTTP over TLS/SSL
)是一種通過計(jì)算機(jī)網(wǎng)絡(luò)進(jìn)行安全通信的傳輸協(xié)議思犁。HTTPS
經(jīng)由 HTTP
進(jìn)行通信,但利用 SSL/TLS
來加密數(shù)據(jù)包高每。HTTPS
開發(fā)的主要目的鹃答,是提供對網(wǎng)站服務(wù)器的身份認(rèn)證,保護(hù)交換數(shù)據(jù)的隱私與完整性李滴。
本文主要介紹 :
-
Https
如何保證數(shù)據(jù)傳輸?shù)陌踩?/li> -
CA
的存在及其安全性 - 證書工具
keytool
- 證書驗(yàn)證流程
-
Https
握手流程 -
Android
下進(jìn)行Https
訪問
TLS/SSL
TCP (Transmission Control Protoco)
傳輸層控制協(xié)議
TLS (Transport Layer Security)
傳輸層安全協(xié)定
SSL (Secure Socket Layer)
安全套接層
HTTP(Hypertext Transfer Protocol)
基于 TCP
協(xié)議螃宙,無連接,每次連接只處理一個(gè)請求所坯,結(jié)束后斷開連接谆扎;無狀態(tài),無法保持用戶狀態(tài)芹助,使用 cookie
和 session
解決堂湖。
HTTPS(HTTP over TLS/SSL)
安全的 http
協(xié)議闲先,HTTP
協(xié)議和 TCP
協(xié)議之間增加了 TLS/SSL
保證數(shù)據(jù)的安全傳輸。
歷史進(jìn)程:
1994年无蜂,NetScape公司設(shè)計(jì)了SSL協(xié)議(Secure Sockets Layer)的1.0版伺糠,但是未發(fā)布。
1995年斥季,NetScape公司發(fā)布SSL 2.0版训桶,很快發(fā)現(xiàn)有嚴(yán)重漏洞。
1996年酣倾,SSL 3.0版問世舵揭,得到大規(guī)模應(yīng)用。
1999年躁锡,互聯(lián)網(wǎng)標(biāo)準(zhǔn)化組織ISOC接替NetScape公司午绳,發(fā)布了SSL的升級版TLS 1.0版。
2006年和2008年映之,TLS進(jìn)行了兩次升級拦焚,分別為TLS 1.1版和TLS 1.2版。最新的變動(dòng)是2011年TLS
1.2的修訂版杠输。
TLS 1.0通常被標(biāo)示為SSL 3.1赎败,TLS 1.1為SSL 3.2,TLS 1.2為SSL 3.3抬伺。
目前螟够,應(yīng)用最廣泛的是TLS 1.0,接下來是SSL 3.0峡钓。但是妓笙,主流瀏覽器都已經(jīng)實(shí)現(xiàn)了TLS 1.2的支持。
Https 安全性
HTTP 協(xié)議的不安全性體現(xiàn)在 3 個(gè)方面:
風(fēng)險(xiǎn) | 描述 | https解決方案 |
---|---|---|
竊聽風(fēng)險(xiǎn) | 攻擊者可以獲知消息內(nèi)容 | 消息加密 |
篡改風(fēng)險(xiǎn) | 攻擊者可以篡改消息內(nèi)容 | 消息摘要 |
冒充風(fēng)險(xiǎn) | 攻擊者可以冒充其他人參與通信 | CA 身份認(rèn)證 |
CA 不可信 | 信任的 CA 亂簽發(fā)證書 | 證書鎖 |
竊聽/嗅探
指的是路由上的攻擊者能岩,可以偷窺到傳輸?shù)南?nèi)容寞宫。
解決方案:
使用對稱加密算法加密通信內(nèi)容,竊聽者獲取到消息也無法識別拉鹃,存在問題 -> 密鑰傳遞的安全性辈赋,在網(wǎng)絡(luò)上面的通信雙方都是陌生人,無法識別身份膏燕,密鑰要通過網(wǎng)絡(luò)傳輸時(shí)很有可能被竊取钥屈。?
使用非對稱加密算法加密通信內(nèi)容,發(fā)布的公鑰用來加密坝辫,私鑰用來解密篷就,即使公鑰被竊取,依然無法解密消息內(nèi)容近忙。存在問題 -> 速度慢竭业,消耗大智润;公鑰被公開,如果回發(fā)私鑰加密的信息未辆,任何持有公鑰的人都可以解密窟绷。?
最終,消息內(nèi)容仍舊使用對稱加密算法來加密咐柜,但是前期對稱加密的密鑰交換使用非對稱加密來進(jìn)行兼蜈,客戶端使用服務(wù)端公鑰加密對稱加密的密鑰固灵,這樣就只有擁有私鑰的服務(wù)端可以獲取到加密內(nèi)容穷蛹,由于對稱加密密鑰長度有限,加密的時(shí)間可以忽略不計(jì)。?
以上献宫,可以防止嗅探的問題,路由上面的攻擊者即使獲取到消息也無法識別消息的內(nèi)容实撒。
消息篡改
消息加密以后攻擊者無法獲取消息內(nèi)容的含義姊途,但是可以篡改消息內(nèi)容,篡改之后接收方也無法感知知态。
解決方案:
- 采用 消息摘要(見文末注腳) 算法可以驗(yàn)證數(shù)據(jù)的完整性捷兰,我們將發(fā)送的消息進(jìn)行摘要,連同消息一起發(fā)送給接收方负敏,接收方拿到消息之后對消息做同樣的摘要處理贡茅,對比摘要結(jié)果,即可知道消息有沒有被篡改其做。
以上顶考,可以解決消息完整性和真實(shí)性的問題。
中間人攻擊
中間人攻擊(Man-in-the-middle Attack妖泄,MITM
)指的是攻擊者在鏈路上偽裝自己驹沿,與通訊雙方分別建立聯(lián)系,并交換其所收到的數(shù)據(jù)蹈胡,使通訊的兩端認(rèn)為他們正在通過一個(gè)私密的連接與對方直接對話渊季,但事實(shí)上整個(gè)會話都被攻擊者完全控制。
作為 A 和 B 通信路由上的攻擊者 M罚渐,作為中間人偽造自己的身份却汉。A 向 B 請求用于通信的 PK_A
,但是被中間人 M 截獲荷并,他偽造生成了假的公鑰 PK_M
合砂,發(fā)送給了 A,同時(shí)向 B 請求并獲取了 B 的公開密鑰 PK_B
璧坟,原來安全的通信過程 <span class="spec">A(使用 PK_B
加密) -> 安全 -> B(使用 SK_B
解密)</span>既穆,現(xiàn)在變成了 <span class="spec">A(使用 PK_M
加密) -> M(使用 SK_M
解密獲取明文內(nèi)容赎懦,再用 PK_B
加密,可能篡改數(shù)據(jù)) -> B(使用 SK_B
解密)</span>幻工。
出現(xiàn)問題的原因在于励两,密鑰在交換的初期是不安全的,網(wǎng)絡(luò)上的通信雙方囊颅,無法確定對方的身份当悔,即無法獲悉當(dāng)前的公鑰是不是自己想要的公鑰。
解決方案:
引入第三方公正作信用背書踢代,第三方公正具有權(quán)威性盲憎,他和通信雙方?jīng)]有關(guān)系,接收方無條件信任公證機(jī)構(gòu)胳挎,也就會信任他簽名的信息饼疙。這種機(jī)構(gòu)被稱為
CA(Certificate Authority
機(jī)構(gòu),即數(shù)字證書認(rèn)證機(jī)構(gòu)慕爬。CA
機(jī)構(gòu)與瀏覽器和操作系統(tǒng)廠商合作窑眯,將公鑰內(nèi)置在瀏覽器和操作系統(tǒng)中,也就是不走網(wǎng)絡(luò)傳輸了医窿,這樣一定程度上保證了公鑰不會被竊取篡改磅甩。服務(wù)端
Server
將自己的消息(消息內(nèi)容大致包括電子簽證機(jī)關(guān)的信息、公鑰用戶信息姥卢、公鑰卷要、權(quán)威機(jī)構(gòu)的簽字和有效期等)進(jìn)行摘要之后,發(fā)給CA
機(jī)構(gòu)AUTH
簽發(fā)證書独榴,Server
使用自己的私鑰對消息摘要加密僧叉,形成證書,并將證書和消息內(nèi)容發(fā)送給Client
括眠,Client
收到后彪标,發(fā)現(xiàn)是AUTH
的證書,同時(shí)對AUTH
是信任的掷豺,則會使用AUTH
的公鑰對證書進(jìn)行解密(這里涉及證書鏈的驗(yàn)證捞烟,其實(shí)要更加復(fù)雜),獲取到消息摘要当船,同時(shí)對收到的消息進(jìn)行摘要题画,對比,如果一致則說明內(nèi)容沒有被篡改德频,是可信的苍息,因?yàn)樯杉用軘?shù)據(jù)的私鑰只有CA
機(jī)構(gòu)才有,這一過程稱為驗(yàn)證數(shù)字簽名。
以上竞思,可以解決中間人攻擊的文圖表谊,另外涉及到非對稱加密的兩種應(yīng)用場景,詳細(xì)介紹見文末非對稱加密應(yīng)用場景盖喷。
CA 錯(cuò)誤簽發(fā)
受信任的 CA
(證書頒發(fā)機(jī)構(gòu))有好幾百個(gè)爆办,他們成為整個(gè)網(wǎng)站身份認(rèn)證過程中一個(gè)較大的攻擊面。實(shí)際上课梳,目前由于 CA
失誤導(dǎo)致錯(cuò)誤簽發(fā)證書距辆,以及個(gè)別 CA
出于某些目的(如監(jiān)控加密流量)故意向第三方隨意簽發(fā)證書這兩種情況時(shí)有發(fā)生。現(xiàn)有的證書信任鏈機(jī)制最大的問題是暮刃,任何一家受信任的 CA
都可以簽發(fā)任意網(wǎng)站的站點(diǎn)證書跨算,這些證書在客戶端看來,都是合法的椭懊,是可以通過驗(yàn)證的诸蚕。
解決方案:
證書鎖(
Certificate Pinning
),證書鎖是為了防范由 「偽造或不正當(dāng)手段獲得網(wǎng)站證書」 造成的中間人攻擊灾搏。證書鎖類似于
HPKP
技術(shù)(下面有簡單介紹)挫望,給予我們主動(dòng)選擇信任CA
的權(quán)利。它的工作原理就是使用預(yù)先設(shè)置的證書指紋和服務(wù)器傳過來的證書鏈中的證書指紋進(jìn)行匹配狂窑,只要有任何一對指紋匹配成功,則認(rèn)為是一次合法的連接桑腮,否則禁止本次鏈接泉哈。也就是說,使用證書鎖之后破讨,不是所有被系統(tǒng)信任的
CA
都可以通過驗(yàn)證丛晦,只有我保存了指紋的一些CA
簽發(fā)的證書才可以,比如有 100 個(gè)CA
機(jī)構(gòu)提陶,但我就信任其中一個(gè)烫沙,我可以保證這個(gè)CA
不會亂簽發(fā)證書,那我就只保存這個(gè)CA
的指紋隙笆,即使攻擊者從其他的 99 個(gè)CA
簽發(fā)證書锌蓄,對我進(jìn)行攻擊,也無法完成連接撑柔。證書鎖定增加了安全性瘸爽,但限制了你的服務(wù)器團(tuán)隊(duì)升級
TLS
證書的能力。
以上铅忿,可以解決 CA
機(jī)構(gòu)簽發(fā)證書權(quán)威性不足的問題剪决,相關(guān)解決方案詳見文末 簽發(fā)證書權(quán)威性問題
?? 綜上,對稱加密通信 + 非對稱加密交換密鑰 + CA 認(rèn)證身份 + 證書鎖鎖定證書指紋 共同保證了 https 的安全性。
CA 安全性
作為全網(wǎng) https
連接的權(quán)威公正柑潦,CA
的安全性至關(guān)重要享言。
安全保存 CA
從根 CA
開始到直接給客戶發(fā)放證書的各層次 CA
,都有其自身的密鑰對渗鬼。CA
中心的密鑰對一般由硬件加密服務(wù)器在機(jī)器內(nèi)直接產(chǎn)生览露,并存儲于加密硬件內(nèi),或以一定的加密形式存放于密鑰數(shù)據(jù)庫內(nèi)乍钻。加密備份于 IC
卡或其他存儲介質(zhì)中肛循,并以高等級的物理安全措施保護(hù)起來。
密鑰的銷毀要以安全的密鑰沖寫標(biāo)準(zhǔn)银择,徹底清除原有的密鑰痕跡多糠。需要強(qiáng)調(diào)的是,根 CA
密鑰的安全性至關(guān)重要浩考,它的泄露意味著整個(gè)公鑰信任體系的崩潰夹孔,所以 CA
的密鑰保護(hù)必須按照最高安全級的保護(hù)方式來進(jìn)行設(shè)置和管理。CA
的私鑰是自己靠上述方法保管的析孽,不對外公開搭伤。
所以 CA
密鑰的安全性依賴于物理硬件的安全性,不通過網(wǎng)絡(luò)傳輸避免了被攻擊的可能袜瞬。
CA
的公鑰是廠商跟瀏覽器和操作系統(tǒng)合作怜俐,把公鑰默認(rèn)裝到瀏覽器或者操作系統(tǒng)環(huán)境里。比如 firefox
就自己維護(hù)了一個(gè)可信任的 CA
列表邓尤,而 chrome
和 IE
使用的是操作系統(tǒng)的 CA
列表拍鲤。
證書鏈
現(xiàn)在大的 CA
都會有證書鏈,證書鏈的好處一是安全汞扎,保持根 CA
的私鑰離線使用季稳。第二個(gè)好處是方便部署和撤銷,即如果證書出現(xiàn)問題澈魄,只需要撤銷相應(yīng)級別的證書景鼠,根證書依然安全。
根 CA
證書都是自簽名痹扇,即用自己的公鑰和私鑰完成了簽名的制作和驗(yàn)證铛漓。而證書鏈上的證書簽名都是使用上一級證書的密鑰對完成簽名和驗(yàn)證的。
證書驗(yàn)證
證書是否是信任的有效證書
是否信任 :接收方內(nèi)置了信任根證書的公鑰帘营,需要證書是不是這些信任根證書簽發(fā)的或者信任根證書的二級證書機(jī)構(gòu)頒發(fā)的票渠。
是否有效:證書是否在有效期內(nèi)。
是否合法:對方是不是上述證書的合法持有者芬迄,證明對方是否持有證書的對應(yīng)私鑰问顷。驗(yàn)證方法兩種,一種是對方簽個(gè)名,我用證書驗(yàn)證簽名杜窄;另外一種是用證書做個(gè)信封肠骆,看對方是否能解開。
是否吊銷:驗(yàn)證是否吊銷可以采用黑名單方式或者
OCSP
方式塞耕。黑名單就是定期從CA
下載一個(gè)名單列表蚀腿,里面有吊銷的證書序列號,自己在本地比對一下就行扫外。優(yōu)點(diǎn)是效率高莉钙。缺點(diǎn)是不實(shí)時(shí)。OCSP
是實(shí)時(shí)連接CA
去驗(yàn)證筛谚,優(yōu)點(diǎn)是實(shí)時(shí)磁玉,缺點(diǎn)是效率不高。
自簽名證書如何驗(yàn)證
自簽名證書是自己給自己簽發(fā)的證書驾讲,也就是說自己做自己的 CA
機(jī)構(gòu)蚊伞,為自己擔(dān)保,因此無法內(nèi)置在系統(tǒng)當(dāng)中吮铭,因此我們通常會在客戶內(nèi)置一個(gè)證書文件时迫,自己進(jìn)行校驗(yàn)。
簡單來說谓晌,握手流程需要兩對密鑰對:
- 一對
CA
的密鑰對JKS_A
掠拳,由CA
機(jī)構(gòu)維護(hù),通常他的公鑰內(nèi)置在os
中纸肉,用來簽名服務(wù)端信息摘要碳想,保證服務(wù)端公鑰的真實(shí)性,避免中間人攻擊毁靶。 - 一對服務(wù)器的密鑰對
JKS_B
,他是握手過程中隨機(jī)生成的逊移,然后用「它的公鑰及其他內(nèi)容」的摘要去向CA
實(shí)時(shí)簽發(fā)證書预吆,用來進(jìn)行對稱密鑰的加密傳輸。
自簽名證書就是不走 CA
機(jī)構(gòu)胳泉,而是自己生成一對密鑰對 JKS_C
拐叉,他的作用就好比 CA
的密鑰對 JKS_A
,也是為了保證公鑰的真實(shí)性扇商,握手過程和原來一樣凤瘦,只是我們不需要去 CA
簽發(fā)證書了,用自己的 JKS_C
簽發(fā)就可以了案铺;同樣因?yàn)?JKS_C
是我們自己的密鑰對蔬芥,公鑰沒有被內(nèi)置在 os
中,所以此時(shí)需要我們自己把 cert
文件(JKS_C
的公鑰)放到本地,自己完成原本由 os
完成的 CA
校驗(yàn)任務(wù)笔诵。
雙向驗(yàn)證
雙向驗(yàn)證指的是返吻,不光客戶端要驗(yàn)證來自服務(wù)器的連接是不是可靠,服務(wù)器也要驗(yàn)證客戶端乎婿。
服務(wù)端也會內(nèi)置一套受信任的 CA
證書列表测僵,用于驗(yàn)證客戶端證書的真實(shí)性。驗(yàn)證過程和客戶端驗(yàn)證服務(wù)端類似谢翎。
Https 握手
單向驗(yàn)證握手過程:
- 1捍靠、Client Hello ??
客戶端向服務(wù)器發(fā)送握手信息,告知自己支持的加密算法森逮、摘要算法榨婆、安全層協(xié)議版本、隨機(jī)數(shù)
Random-Secret-C
吊宋。
- 2纲辽、Server Hello ??
服務(wù)端隨機(jī)生成本次握手需要的非對稱加密的密鑰對(私鑰+公鑰),將來用來傳輸對稱加密密鑰璃搜。
服務(wù)端生成消息拖吼,內(nèi)容包含隨機(jī)數(shù)
Random-Secret-S
,確定的一組加密算法和摘要算法这吻,服務(wù)端公鑰吊档,域名信息等。
服務(wù)端對信息內(nèi)容摘要唾糯,使用摘要的信息向 CA 機(jī)構(gòu)申請的簽名證書怠硼。
服務(wù)端向客戶端發(fā)送消息和申請的證書。
如果需要雙向驗(yàn)證的話移怯,請求客戶端證書香璃。
- 3、驗(yàn)證服務(wù)端證書舟误,提取服務(wù)端公鑰 ??
客戶端從信任證書列表中發(fā)現(xiàn)是受信任的證書葡秒,會首先驗(yàn)證證書是否被信任、有效性嵌溢、合法性等信息眯牧,驗(yàn)證過程參照上面的 證書驗(yàn)證。
驗(yàn)證通過赖草,客戶端使用
CA
機(jī)構(gòu)的公鑰對證書解密学少,拿到消息的摘要,對真正的消息內(nèi)容進(jìn)行摘要秧骑,對比確定消息沒有被篡改版确,則取出服務(wù)端公鑰扣囊。
如果需要雙向驗(yàn)證的話,向服務(wù)端發(fā)送自己的證書阀坏。
客戶端生成隨機(jī)數(shù)字
Pre-Master-Secret
如暖,將其進(jìn)行摘要處理,使用服務(wù)端公鑰對消息和摘要結(jié)果加密忌堂,發(fā)送給服務(wù)器盒至,并發(fā)送一個(gè)編碼改變通知,說明以后將會開始加密通信士修。
- 4枷遂、生成對稱加密密鑰 ??
如果需要雙向驗(yàn)證的話,首先驗(yàn)證客戶端證書棋嘲,驗(yàn)證過程類似客戶端驗(yàn)證酒唉,驗(yàn)證失敗則斷開連接
服務(wù)器使用私鑰對收到的信息解密,對消息進(jìn)行摘要對比無誤沸移,則說明對稱加密的密鑰沒有被篡改痪伦,然后使用
Random-Secret-C
,Random-Secret-S
,Pre-Master-Secret
生成最終將要進(jìn)行對稱加密通信的密鑰Master-Secret
。
服務(wù)器使用
Master-Secret
加密一段握手信息及其摘要雹锣,發(fā)送給客戶端网沾,并發(fā)送一個(gè)編碼改變通知,說明以后將會開始加密通信蕊爵。
- 5辉哥、客戶端驗(yàn)證加密結(jié)果,握手結(jié)束 ??
客戶端使用
Random-Secret-C
,Random-Secret-S
,Pre-Master-Secret
生成同樣的對稱加密密鑰Master-Secret
攒射,使用密鑰解密醋旦,并驗(yàn)證信息摘要,沒有問題則握手結(jié)束会放。
后面的通信將會使用新生成的對稱加密密鑰加密進(jìn)行饲齐。
圖解:
問題記錄
Q:為什么要有 3 個(gè)隨機(jī)數(shù)?
不管是客戶端還是服務(wù)器咧最,都需要隨機(jī)數(shù)箩张,這樣生成的密鑰才不會每次都一樣。由于
SSL
協(xié)議中證書是靜態(tài)的窗市,因此十分有必要引入一種隨機(jī)因素來保證協(xié)商出來的密鑰的隨機(jī)性。對于RSA密鑰交換算法來說饮笛,Pre-Master-Secret
本身就是一個(gè)隨機(jī)數(shù)咨察,再加上hello
消息中的隨機(jī),三個(gè)隨機(jī)數(shù)通過一個(gè)密鑰導(dǎo)出器最終導(dǎo)出一個(gè)對稱密鑰福青。
Pre-Master
的存在在于SSL
協(xié)議不信任每個(gè)主機(jī)都能產(chǎn)生完全隨機(jī)的隨機(jī)數(shù)摄狱,如果隨機(jī)數(shù)不隨機(jī)脓诡,那么Pre-Master-Secret
就有可能被猜出來,那么僅適用Pre-Master-Secret
作為密鑰就不合適了媒役,因此必須引入新的隨機(jī)因素祝谚,那么客戶端和服務(wù)器加上Pre-Master-Secret
三個(gè)隨機(jī)數(shù)一同生成的密鑰就不容易被猜出了,一個(gè)偽隨機(jī)可能完全不隨機(jī)酣衷,可是是三個(gè)偽隨機(jī)就十分接近隨機(jī)了交惯,每增加一個(gè)自由度,隨機(jī)性增加的可不是一穿仪。"
Q:放在 Android
客戶端的 cert
文件是啥席爽?
是自簽名證書的公鑰,自簽名證書就是自己做自己的
CA
機(jī)構(gòu)啊片,服務(wù)端會自己維護(hù)一個(gè)密鑰對JKS
只锻,他就相當(dāng)于CA
的簽發(fā)證書的密鑰對,在握手過程中服務(wù)器不需要走CA
申請簽名證書了紫谷,自己簽發(fā)就可以齐饮,原本CA
的公鑰被內(nèi)置在os
中,CA
的驗(yàn)證不需要我們來關(guān)注笤昨,但是現(xiàn)在是自簽名的祖驱,自己做自己的CA
,所以JKS
的公鑰我們要內(nèi)置在客戶端中咬腋,自己完成驗(yàn)證過程羹膳,替代原來os
的驗(yàn)證。
證書工具-keytool
提取證書內(nèi)容為一個(gè)字符串
keytool -printcert -rfc -file [srca.cer]
生成密鑰對
keytool -genkey -alias [march_server] -keyalg RSA -keystore [march_server.jks] -validity 3600 -storepass [123456]
讀取密鑰對信息
keytool -list -v -keystore [srca.jks] -storepass [123456]
提取公鑰根竿,簽發(fā) cert
文件
keytool -export -alias march_server -file march_server.cer -keystore march_server.jks -storepass 123456
將客戶端公鑰導(dǎo)入客戶端密鑰對中陵像,主要是服務(wù)器不能使用 cert
證書,需要導(dǎo)入到 jks
文件中
keytool -import -alias [march_client] -file [march_client.cer] -keystore [march_client_for_server.jks]
搭建 https 服務(wù)
這部分內(nèi)容參考了 CSDN-hongyang-Android Https 完全解析寇壳,這里做一個(gè)匯總和整理醒颖。
借助 tomcat
搭建簡單的 https
服務(wù),主要是用來測試壳炎,之前使用 12306
的證書測試泞歉,但是前段時(shí)間 12306
證書換掉了,現(xiàn)在已經(jīng)是正式證書了匿辩,所以不得以需要自己搭建一個(gè)簡單的服務(wù)來做訪問測試腰耙。
- 搭建單向驗(yàn)證的
https
服務(wù)
首先我們準(zhǔn)備好密鑰和證書,使用 keytool
工具生成服務(wù)端 march_server.jks
密鑰對铲球,然后提取服務(wù)端公鑰 march_server.cert
挺庞。
配置服務(wù),主要是配置 tomcat/conf/server.xml
文件稼病,添加一個(gè)如下的 Connector
选侨。
<!--
https 測試服務(wù)
clientAuth 和 truststoreFile 配置服務(wù)器驗(yàn)證客戶端
keystoreFile 和 keystorePass 配置客戶端驗(yàn)證服務(wù)器
-->
<Connector
clientAuth="false"
keystoreFile="/Users/march/Documents/march_server.jks"
keystorePass="123456"
disableUploadTimeout="true"
enableLookups="true"
SSLEnabled="true"
acceptCount="100"
maxSpareThreads="75"
maxThreads="200"
minSpareThreads="5"
protocol="org.apache.coyote.http11.Http11NioProtocol"
scheme="https"
secure="true"
port="8443"
sslProtocol="TLS"/>
- 搭建雙向驗(yàn)證的
https
服務(wù)
再生成客戶端密鑰對 march_client.jks
掖鱼,然后簽發(fā)客戶端公鑰 march_client.cert
,為了能在服務(wù)端使用援制,將 march_client.cert
導(dǎo)入到新的密鑰對 march_client_for_server.jks
戏挡。使用的命令都可以在上一節(jié)找到,生成這幾個(gè)密鑰晨仑,是為了搭建后面的服務(wù)作準(zhǔn)備褐墅。
更改 conf/server.xml
配置
<!--
https 測試服務(wù)
clientAuth 和 truststoreFile 配置服務(wù)器驗(yàn)證客戶端
keystoreFile 和 keystorePass 配置客戶端驗(yàn)證服務(wù)器
-->
<Connector
clientAuth="true"
truststoreFile="/Users/march/Documents/march_client_for_server.jks"
keystoreFile="/Users/march/Documents/march_server.jks"
keystorePass="123456"
disableUploadTimeout="true"
enableLookups="true"
SSLEnabled="true"
acceptCount="100"
maxSpareThreads="75"
maxThreads="200"
minSpareThreads="5"
protocol="org.apache.coyote.http11.Http11NioProtocol"
scheme="https"
secure="true"
port="8443"
sslProtocol="TLS"/>
此時(shí)瀏覽器已經(jīng)不能訪問
Android 進(jìn)行 Https 訪問
如果你的證書是購買的 CA
簽發(fā)的證書,是可以直接進(jìn)行 https
訪問的寻歧,不需要做什么特殊處理掌栅,下面主要介紹使用自簽名證書的情況。
啟用雙向驗(yàn)證時(shí)码泛,Android
客戶端也不能直接使用 march_client.jks
需要轉(zhuǎn)為 bks
文件猾封,使用下面的工具。jks 轉(zhuǎn) bks 工具
注:這部分不是說如何發(fā)請求噪珊,只是討論怎么配置證書和密鑰對去發(fā)起 Https 訪問晌缘。
在 Android
中進(jìn)行 Https
訪問,主要牽扯到以下幾個(gè)關(guān)鍵類:
-
TrustManagerFactory
痢站,它主要是用來導(dǎo)入自簽名證書磷箕,用來驗(yàn)證來自服務(wù)器的連接。 -
KeyManagerFactory
阵难,當(dāng)開啟雙向驗(yàn)證時(shí)岳枷,用來導(dǎo)入客戶端的密鑰對。 -
SSLContext
呜叫,SSL
上下文空繁,使用上面的兩個(gè)類進(jìn)行初始化,就是個(gè)上下文環(huán)境朱庆。
?? 都讓開盛泡,我要貼代碼了!
SSLContext
為了簡單起見娱颊,我們先來看看如何生成 SSLContext
/**
* 創(chuàng)建 SSLContext
* @param keyManagerFactory 用于雙向驗(yàn)證傲诵,不需要可以直接為空
* @param trustManagerFactory 用于導(dǎo)入證書
* @return SSLContext
*/
private SSLContext getSSLContext(@Nullable KeyManagerFactory keyManagerFactory,
TrustManagerFactory trustManagerFactory)
throws NoSuchAlgorithmException, KeyManagementException {
if (trustManagerFactory == null)
return null;
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManager[] keyManagers = null;
if (keyManagerFactory != null) {
keyManagers = keyManagerFactory.getKeyManagers();
}
sslContext.init(keyManagers, trustManagerFactory.getTrustManagers(), new SecureRandom());
return sslContext;
}
TrustManagerFactory
導(dǎo)入客戶端證書,生成 TrustManagerFactory
/**
* 導(dǎo)入客戶端證書箱硕,生成 TrustManagerFactory
* @param serverCertInputStreams 證書的輸入流
* @return TrustManagerFactory
*/
private TrustManagerFactory getTrustManagerFactory(InputStream... serverCertInputStreams)
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
if (serverCertInputStreams == null || serverCertInputStreams.length == 0) {
return null;
}
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
// 為證書設(shè)置一個(gè)keyStore拴竹,并將證書放入 keyStore 中
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
int index = 0;
for (InputStream inputStream : serverCertInputStreams) {
String alias = Integer.toString(index++);
Certificate certificate = certificateFactory.generateCertificate(inputStream);
keyStore.setCertificateEntry(alias, certificate);
}
// 創(chuàng)建 TrustManagerFactory
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
return trustManagerFactory;
}
KeyManagerFactory
雙向驗(yàn)證時(shí),配置客戶端密鑰對剧罩,生成 KeyManagerFactory
/**
* 雙向驗(yàn)證時(shí)殖熟,配置客戶端密鑰對,生成 KeyManagerFactory
*
* @param clientCertInputStream 密鑰對輸入流
* @param passWd 密鑰對密碼
* @return KeyManagerFactory
*/
private KeyManagerFactory getKeyManagerFactory(InputStream clientCertInputStream, String passWd)
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException {
if (clientCertInputStream == null || passWd == null) {
return null;
}
//本地證書 初始化keystore
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
clientKeyStore.load(clientCertInputStream, passWd.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, passWd.toCharArray());
return keyManagerFactory;
}
Init Connection
這樣我們就拿到了已經(jīng)生成好的 SSLContext
斑响,我們需要的 KeyManagerFactory
菱属,TrustManagerFactory
都已經(jīng)加到 SSLContext
里面了。
如果是用 HttpsURLConnection
connection.setSSLSocketFactory(sslContext.getSocketFactory());
如果是用 OkHttp
// 這個(gè)方法已經(jīng)過時(shí)了
okHttpClientBuilder.sslSocketFactory(sslContext.getSocketFactory());
// 新的方法需要一個(gè) X509TrustManager舰罚,那我們就從 TrustManagerFactory 取出來給他
TrustManagerFactory trustManagerFactory = getTrustManagerFactory(serverCertInputStreams);
KeyManagerFactory keyManagerFactory = getKeyManagerFactory(clientCertInputStream, passWd);
if (trustManagerFactory != null) {
X509TrustManager x509TrustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
SSLContext sslContext = getSSLContext(keyManagerFactory, trustManagerFactory);
if (x509TrustManager != null && sslContext != null) {
okHttpClientBuilder.sslSocketFactory(sslContext.getSocketFactory(), x509TrustManager);
}
}
HostnameVerifier
另外 HostnameVerifier
也是必要的纽门,這個(gè) HttpsURLConnection
和 OkHttp
沒啥差別
connection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
okHttpClientBuilder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
巨人的肩膀
CSDN 如何理解HTTP協(xié)議的 “無連接,無狀態(tài)” 特點(diǎn)营罢?
個(gè)人博客-餓了么Android-聊聊 Android HTTPS 的使用姿勢
個(gè)人博客-https詳解 概要介紹
CSDN-hongyang-Android Https 完全解析
阮一峰-SSL/TLS協(xié)議運(yùn)行機(jī)制的概述
注腳
<span id="消息摘要"/>
消息摘要(Message Digest)
指的是將長度不固定的參數(shù)作為輸入?yún)?shù),運(yùn)行特定 hash 函數(shù)饲漾,生成固定長度的輸出蝙搔,這個(gè)輸出就是消息的摘要,常用算法有 MD5
和 SHA1
考传,摘要算法是單向不可逆的吃型,即無法從摘要重新反向出原消息的內(nèi)容。
<span id="信用背書"/>
信用背書
票據(jù)的收款人或持有人在轉(zhuǎn)讓票據(jù)時(shí)僚楞,在票據(jù)背面簽名或書寫文句的手續(xù)勤晚。背書的人就會對這張支票負(fù)某種程度、類似擔(dān)保的償還責(zé)任泉褐。
<span id="非對稱加密應(yīng)用場景"/>
非對稱加密的兩種應(yīng)用場景
- 某用戶使用自己的私鑰對數(shù)據(jù)加密赐写,任何人都可以使用公鑰對數(shù)據(jù)進(jìn)行解密,因?yàn)樗借€只有該用戶持有膜赃,則說明該數(shù)據(jù)一定出自于該用戶挺邀。公眾可以用這一方法驗(yàn)證內(nèi)容是否完整,是否被篡改跳座,接受者可以認(rèn)定該內(nèi)容出自該用戶端铛,該用戶也無法抵賴,這被稱作數(shù)字簽名躺坟。
- 某用戶使用公開的公鑰對數(shù)據(jù)進(jìn)行加密沦补,那么可以保證只有發(fā)布公鑰的一方可以對數(shù)據(jù)進(jìn)行解密,別人無法獲取數(shù)據(jù)的內(nèi)容咪橙,保證數(shù)據(jù)傳遞的安全夕膀。
<span id="簽發(fā)證書權(quán)威性問題"/>
應(yīng)對 CA 簽發(fā)證書權(quán)威性問題的解決方案