Https 詳解

超文本傳輸安全協(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)芹助,使用 cookiesession 解決堂湖。

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)容寞宫。

解決方案:

  1. 使用對稱加密算法加密通信內(nèi)容,竊聽者獲取到消息也無法識別拉鹃,存在問題 -> 密鑰傳遞的安全性辈赋,在網(wǎng)絡(luò)上面的通信雙方都是陌生人,無法識別身份膏燕,密鑰要通過網(wǎng)絡(luò)傳輸時(shí)很有可能被竊取钥屈。?

  2. 使用非對稱加密算法加密通信內(nèi)容,發(fā)布的公鑰用來加密坝辫,私鑰用來解密篷就,即使公鑰被竊取,依然無法解密消息內(nèi)容近忙。存在問題 -> 速度慢竭业,消耗大智润;公鑰被公開,如果回發(fā)私鑰加密的信息未辆,任何持有公鑰的人都可以解密窟绷。?

  3. 最終,消息內(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è)會話都被攻擊者完全控制。

作為 AB 通信路由上的攻擊者 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 列表邓尤,而 chromeIE 使用的是操作系統(tǒng)的 CA 列表拍鲤。

證書鏈

現(xiàn)在大的 CA 都會有證書鏈,證書鏈的好處一是安全汞扎,保持根 CA 的私鑰離線使用季稳。第二個(gè)好處是方便部署和撤銷,即如果證書出現(xiàn)問題澈魄,只需要撤銷相應(yīng)級別的證書景鼠,根證書依然安全。

CA 證書都是自簽名痹扇,即用自己的公鑰和私鑰完成了簽名的制作和驗(yàn)證铛漓。而證書鏈上的證書簽名都是使用上一級證書的密鑰對完成簽名和驗(yàn)證的。

證書驗(yàn)證

證書是否是信任的有效證書

  1. 是否信任 :接收方內(nèi)置了信任根證書的公鑰帘营,需要證書是不是這些信任根證書簽發(fā)的或者信任根證書的二級證書機(jī)構(gòu)頒發(fā)的票渠。

  2. 是否有效:證書是否在有效期內(nèi)。

  3. 是否合法:對方是不是上述證書的合法持有者芬迄,證明對方是否持有證書的對應(yīng)私鑰问顷。驗(yàn)證方法兩種,一種是對方簽個(gè)名,我用證書驗(yàn)證簽名杜窄;另外一種是用證書做個(gè)信封肠骆,看對方是否能解開。

  4. 是否吊銷:驗(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)。

簡單來說谓晌,握手流程需要兩對密鑰對:

  1. 一對 CA 的密鑰對 JKS_A掠拳,由 CA 機(jī)構(gòu)維護(hù),通常他的公鑰內(nèi)置在 os 中纸肉,用來簽名服務(wù)端信息摘要碳想,保證服務(wù)端公鑰的真實(shí)性,避免中間人攻擊毁靶。
  2. 一對服務(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)行饲齐。

圖解:

https

問題記錄

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)鍵類:

  1. TrustManagerFactory痢站,它主要是用來導(dǎo)入自簽名證書磷箕,用來驗(yàn)證來自服務(wù)器的連接。
  2. KeyManagerFactory阵难,當(dāng)開啟雙向驗(yàn)證時(shí)岳枷,用來導(dǎo)入客戶端的密鑰對。
  3. 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è) HttpsURLConnectionOkHttp 沒啥差別

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è)故事讓你徹底理解 Https

簡書 HTTPS 是如何保證安全的赏陵?

個(gè)人博客-餓了么Android-聊聊 Android HTTPS 的使用姿勢

個(gè)人博客-細(xì)說 CA 和證書

個(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è)輸出就是消息的摘要,常用算法有 MD5SHA1考传,摘要算法是單向不可逆的吃型,即無法從摘要重新反向出原消息的內(nèi)容。

<span id="信用背書"/>
信用背書

票據(jù)的收款人或持有人在轉(zhuǎn)讓票據(jù)時(shí)僚楞,在票據(jù)背面簽名或書寫文句的手續(xù)勤晚。背書的人就會對這張支票負(fù)某種程度、類似擔(dān)保的償還責(zé)任泉褐。

<span id="非對稱加密應(yīng)用場景"/>
非對稱加密的兩種應(yīng)用場景

  1. 某用戶使用自己的私鑰對數(shù)據(jù)加密赐写,任何人都可以使用公鑰對數(shù)據(jù)進(jìn)行解密,因?yàn)樗借€只有該用戶持有膜赃,則說明該數(shù)據(jù)一定出自于該用戶挺邀。公眾可以用這一方法驗(yàn)證內(nèi)容是否完整,是否被篡改跳座,接受者可以認(rèn)定該內(nèi)容出自該用戶端铛,該用戶也無法抵賴,這被稱作數(shù)字簽名躺坟。
  2. 某用戶使用公開的公鑰對數(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)威性問題的解決方案

  1. Google 推動(dòng)的 Certificate Transparency 技術(shù),它旨在通過開放的審計(jì)和監(jiān)控系統(tǒng)美侦,提高 HTTPS 網(wǎng)站證書安全性产舞。CT 技術(shù)能改善這種情況,但 CT 還沒有普及菠剩,現(xiàn)階段瀏覽器不能貿(mào)然阻斷沒有提供 SCT 信息的 HTTPS 網(wǎng)站易猫。CT 介紹

  2. HTTP Public Key Pinning 技術(shù) HPKP 介紹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市具壮,隨后出現(xiàn)的幾起案子准颓,更是在濱河造成了極大的恐慌哈蝇,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件攘已,死亡現(xiàn)場離奇詭異炮赦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)样勃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門吠勘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人峡眶,你說我怎么就攤上這事剧防。” “怎么了辫樱?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵峭拘,是天一觀的道長。 經(jīng)常有香客問我搏熄,道長棚唆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任心例,我火速辦了婚禮宵凌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘止后。我一直安慰自己瞎惫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布译株。 她就那樣靜靜地躺著瓜喇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪歉糜。 梳的紋絲不亂的頭發(fā)上乘寒,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機(jī)與錄音匪补,去河邊找鬼伞辛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛夯缺,可吹牛的內(nèi)容都是我干的蚤氏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼踊兜,長吁一口氣:“原來是場噩夢啊……” “哼竿滨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤于游,失蹤者是張志新(化名)和其女友劉穎毁葱,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贰剥,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡头谜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸠澈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡截驮,死狀恐怖笑陈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情葵袭,我是刑警寧澤涵妥,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布坡锡,位于F島的核電站蓬网,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鹉勒。R本人自食惡果不足惜帆锋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望禽额。 院中可真熱鬧锯厢,春花似錦、人聲如沸脯倒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藻丢。三九已至剪撬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悠反,已是汗流浹背残黑。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留问慎,地道東北人萍摊。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像如叼,于是被迫代替她去往敵國和親冰木。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 協(xié)議 1、HTTP 協(xié)議(HyperText Transfer Protocol踊沸,超文本傳輸協(xié)議):是客戶端瀏覽器...
    大富帥閱讀 777評論 0 11
  • 前言:在一個(gè)app運(yùn)行時(shí)期,由于android進(jìn)程隔離的原因,每個(gè)應(yīng)用都有自己獨(dú)立的內(nèi)存空間,其他應(yīng)用是無法直接訪...
    松哦哦閱讀 348評論 1 5
  • 本文摘自 騰訊bugly 的文章《全站 HTTPS 來了》,內(nèi)容有修改腺律。 大家在使用百度奕短、谷歌或淘寶的時(shí)候,是否注...
    bnotes閱讀 3,658評論 1 9
  • 愛 (III)喬治·赫伯特, 1593 - 1633 愛向我招手匀钧,我的靈魂卻因骯臟和罪惡而退縮翎碑。但眼光敏銳的愛,察...
    劉叔夜閱讀 772評論 0 1
  • 小時(shí)候,一到大年初二,一大早就跟著爸爸去親戚長輩家拜年佑刷,聊天莉擒,玩牌,吃瓜子花生瘫絮,還有好吃的美味佳肴涨冀,拿長輩給的紅包...
    陽光坤哥閱讀 645評論 20 9