Https理論
在說HTTPS之前先說說什么是HTTP哩牍,HTTP就是我們平時(shí)瀏覽網(wǎng)頁時(shí)候使用的一種協(xié)議试吁。HTTP協(xié)議傳輸?shù)臄?shù)據(jù)都是未加密的霍弹,也就是明文的萍倡,因此使用HTTP協(xié)議傳輸隱私信息非常不安全身弊。為了保證這些隱私數(shù)據(jù)能加密傳輸,于是網(wǎng)景公司設(shè)計(jì)了SSL(Secure Sockets Layer)協(xié)議用于對(duì)HTTP協(xié)議傳輸?shù)臄?shù)據(jù)進(jìn)行加密,從而就誕生了HTTPS佑刷。SSL目前的版本是3.0莉擒,被IETF(Internet Engineering Task Force)定義在RFC 6101中,之后IETF對(duì)SSL 3.0進(jìn)行了升級(jí)瘫絮,于是出現(xiàn)了TLS(Transport Layer Security) 1.0涨冀,定義在RFC 2246。實(shí)際上我們現(xiàn)在的HTTPS都是用的TLS協(xié)議麦萤,但是由于SSL出現(xiàn)的時(shí)間比較早鹿鳖,并且依舊被現(xiàn)在瀏覽器所支持,因此SSL依然是HTTPS的代名詞壮莹,但無論是TLS還是SSL都是上個(gè)世紀(jì)的事情翅帜,SSL最后一個(gè)版本是3.0,今后TLS將會(huì)繼承SSL優(yōu)良血統(tǒng)繼續(xù)為我們進(jìn)行加密服務(wù)命满。目前TLS的版本是1.2涝滴。
Https的工作原理
HTTPS在傳輸數(shù)據(jù)之前需要客戶端(瀏覽器)與服務(wù)端(網(wǎng)站)之間進(jìn)行一次握手,在握手過程中將確立雙方加密傳輸數(shù)據(jù)的密碼信息胶台。TLS/SSL協(xié)議不僅僅是一套加密傳輸?shù)膮f(xié)議歼疮,更是一件經(jīng)過藝術(shù)家精心設(shè)計(jì)的藝術(shù)品,TLS/SSL中使用了非對(duì)稱加密诈唬,對(duì)稱加密以及HASH算法
TCP韩脏、Https、SSL/TLS铸磅、https的關(guān)系
上圖截自維基百科赡矢,對(duì)協(xié)議進(jìn)行了明確的劃分。
TCP
傳輸控制協(xié)議阅仔,屬于傳輸層協(xié)議吹散,提供可靠數(shù)據(jù)傳輸。它為http等應(yīng)用層協(xié)議提供服務(wù)八酒。Http
超文本傳輸協(xié)議空民,屬于應(yīng)用層協(xié)議。依賴于TCP協(xié)議丘跌。SSL/TLS
安全傳輸層協(xié)議袭景,用于在兩個(gè)通信應(yīng)用程序之間提供保密性和數(shù)據(jù)完整性。位于某個(gè)可靠的傳輸協(xié)議(例如 TCP)上面闭树,屬于應(yīng)用層協(xié)議耸棒。Https
在Http和TCP中間加入了SSL/TLS,保證數(shù)據(jù)傳輸?shù)陌踩?/p>
Https抓包演示
上面是我使用Avanced REST client請(qǐng)求我的https接口,整個(gè)請(qǐng)求是沒問題的报辱,后面我們就會(huì)抓下這個(gè)請(qǐng)求的包進(jìn)行分析与殃。
為了方便演示整個(gè)流程,我使用了自己的云服務(wù)器和已備案的域名,證書直接在阿里云上申請(qǐng)的免費(fèi)證書幅疼。
環(huán)境配置
這里web服務(wù)器我們使用Nginx米奸。
首先將阿里下發(fā)的證書放到nginx的conf下(新建一個(gè)cert文件夾)
配置nginx
當(dāng)然我們的后臺(tái)服務(wù)得啟動(dòng)起來。端口9000爽篷。這里我用的Springboot悴晰。
@ApiOperation(value = "測(cè)試POST", notes = "測(cè)試POST")
@RequestMapping(value = "post", method = RequestMethod.POST)
public Result<TestEntity> testPost(@RequestBody TestBody testBody) throws Exception {
Result<TestEntity> result = new Result<TestEntity>();
TestEntity testEntity = new TestEntity();
testEntity.setId(2);
testEntity.setName(testBody.toString());
result.setData(testEntity);
return result;
}
Https握手
我們將前面發(fā)起的請(qǐng)求進(jìn)行抓包,這里使用wireshark逐工。
這是一個(gè)完整的請(qǐng)求抓包铡溪。這樣看,不是很清晰泪喊,我來畫個(gè)圖來表達(dá)下這個(gè)過程發(fā)生了什么棕硫。
三次握手和四次揮手我們就不說了,這個(gè)才講TCP的時(shí)候有詳細(xì)介紹袒啼。
我們一步一步的看
第一步 Client Hello
先看一下抓出來包的內(nèi)容哈扮,我們直接看到SSL層
這一步干啥了呢?
- TLS的版本
- 隨機(jī)數(shù):這個(gè)是用來生成最后加密密鑰的影響因子之一蚓再,包含兩部分:時(shí)間戳(4-Bytes)和隨機(jī)數(shù)(28-Bytes)
- session-id:用來表明一次會(huì)話滑肉,第一次建立沒有。如果以前建立過对途,可以直接帶過去赦邻。后面的擴(kuò)展內(nèi)容會(huì)詳細(xì)講到髓棋。
- 加密算法套裝列表:客戶端支持的加密-簽名算法的列表实檀,讓服務(wù)器去選擇。
- 壓縮算法:似乎一般都不用
- 擴(kuò)展字段:比如密碼交換算法的參數(shù)按声、請(qǐng)求主機(jī)的名字等等
這里要注意一個(gè)隨機(jī)數(shù)膳犹,很重要。我們先記為Random1签则。
第二步 Server Hello
- 據(jù)客戶端支持的SSL/TLS協(xié)議版本须床,和自己的比較確定使用的SSL/TLS協(xié)議版本
- 確定加密套件,壓縮算法
- 產(chǎn)生了一個(gè)隨機(jī)數(shù)Random2。注意渐裂,至此客戶端和服務(wù)端都擁有了兩個(gè)隨機(jī)數(shù)(Random1+ Random2)豺旬,這兩個(gè)隨機(jī)數(shù)會(huì)在后續(xù)生成對(duì)稱秘鑰時(shí)用到
第三步 Server => Client
這次傳輸包含三部分內(nèi)容
- Certificate
- Server Key Exchange
- ServerHello Done
這里也是一個(gè)優(yōu)化,三個(gè)部分一起發(fā)送柒凉。我們一個(gè)個(gè)分析
Certificate
這里主要就是把證書發(fā)送給Client族阅。圖中可以看到我的證書和證書發(fā)放機(jī)構(gòu)∠ダ蹋客戶端拿到證書后就可以進(jìn)行驗(yàn)證坦刀,同時(shí)獲取到公鑰,用于后面Random3的加密。
證書一般采用X.509標(biāo)準(zhǔn)鲤遥。
Server Key Exchange
這個(gè)消息是用來發(fā)送密鑰交換算法相關(guān)參數(shù)和數(shù)據(jù)的沐寺。這里要提前提一下,就是根據(jù)密鑰交換算法的不同盖奈,傳遞的參數(shù)也是不同的混坞。
常用的密鑰交換算法:RSA、DH(Diffie-Hellman)钢坦、ECDH(Ellipticcurve Diffie–Hellman)拔第。
這里看到使用的ECDH。
Server Hello Done
這個(gè)就是Server來表示自己說完了场钉。類似電影里別人拿對(duì)講機(jī)說完話最后會(huì)有一個(gè)“完畢蚊俺!”。
第四步 Client => Server
這次傳輸也包含三部分內(nèi)容逛万,也是做了一個(gè)優(yōu)化
- Client Key Exchange
- Change Cipher Spec
- Encrypted Handshake Message
我們依次解讀
Client Key Exchange
這個(gè)也是交換秘鑰參數(shù)泳猬。
這里客戶端會(huì)再生成一個(gè)隨機(jī)數(shù)Random3。然后使用服務(wù)端傳來的公鑰進(jìn)行加密得到密文PreMaster Key宇植。服務(wù)端收到這個(gè)值后得封,使用私鑰進(jìn)行解密,得到Random3指郁。這樣客戶端和服務(wù)端就都擁有了Random1忙上、Random2和Random3。這樣兩邊的秘鑰就協(xié)商好了闲坎。后面數(shù)據(jù)傳輸就可以用協(xié)商好的秘鑰進(jìn)行加密和解密疫粥。
Change Cipher Spec
編碼改變通知。這一步是客戶端通知服務(wù)端后面再發(fā)送的消息都會(huì)使用前面協(xié)商出來的秘鑰加密了腰懂,是一條事件消息梗逮。
Encrypted Handshake Message
這一步對(duì)應(yīng)的是 Client Finish 消息,客戶端將前面的握手消息生成摘要再用協(xié)商好的秘鑰加密绣溜,這是客戶端發(fā)出的第一條加密消息慷彤。服務(wù)端接收后會(huì)用秘鑰解密,能解出來說明前面協(xié)商出來的秘鑰是一致的怖喻。
第五步 Server => Client
包括三部分
- New Session Ticket
- Change Cipher Spec
- Encrypted Handshake Message
New Session Ticket
包含了一個(gè)加密通信所需要的信息底哗,這些數(shù)據(jù)采用一個(gè)只有服務(wù)器知道的密鑰進(jìn)行加密。目標(biāo)是消除服務(wù)器需要維護(hù)每個(gè)客戶端的會(huì)話狀態(tài)緩存的要求锚沸。這部分內(nèi)容在后面的擴(kuò)展部分會(huì)講到
Change Cipher Spec
編碼改變通知跋选。這一步是服務(wù)端通知客戶端后面再發(fā)送的消息都會(huì)使用加密,也是一條事件消息咒吐。
Encrypted Handshake Message
這一步對(duì)應(yīng)的是 Server Finish 消息野建,服務(wù)端也會(huì)將握手過程的消息生成摘要再用秘鑰加密属划,這是服務(wù)端發(fā)出的第一條加密消息『蛏客戶端接收后會(huì)用秘鑰解密同眯,能解出來說明協(xié)商的秘鑰是一致的。
到這里雙方SSL/TLS握手完成唯鸭。
Https數(shù)據(jù)傳輸
接下來就真正的到了接口請(qǐng)求的階段须蜗。TLS的Content-Type為Application Data。 傳輸?shù)膬?nèi)容也是加密的目溉。
常見問題:
這里對(duì)整個(gè)過程中出現(xiàn)的常見問題做一個(gè)匯總
第四步出現(xiàn)多個(gè)Hello Request消息
我們看到上面最后出現(xiàn)了兩個(gè)Hello Request明肮,估計(jì)很多人用wireshark打開就是這樣的。而Hello Request消息是個(gè)啥東西呢缭付?我們看下權(quán)威文檔:
這寫的很清楚嘛柿估,這是消息應(yīng)該是Server可能隨時(shí)發(fā)給Client的。到我們這來怎么變成Client發(fā)給Server了陷猫,而且和消息的解析牛頭不對(duì)馬腳秫舌。
我們?cè)僦販叵挛覀兊牧鞒?br>
客戶端發(fā)送了Change Cipher Spec后,后面的內(nèi)容就是加密的绣檬,而加密后的內(nèi)容wireshark無法解析識(shí)別足陨。而這些二進(jìn)制數(shù)據(jù)就別誤解析為Hello Request。我們看下Hello Request的類型枚舉值:
hello_request(0)
所以我覺得應(yīng)該是wireshake誤認(rèn)為是hello request消息
既然知道問題娇未,那怎么解決呢墨缘?
這里需要我們把私鑰添加到wireshark中:
【編輯】-》【首選項(xiàng)】-》【SSL】-》【Edit】
然后將私鑰添加進(jìn)來
這樣就搞定了梭姓。
拓展內(nèi)容
這部分對(duì)Https做一個(gè)深入的了解
TLS會(huì)話恢復(fù)
完整的TLS握手需要額外延遲和計(jì)算颈娜,為所有需要安全通信的應(yīng)用帶來了嚴(yán)重的性能損耗。為了幫助減少一些性能損耗葱轩,TLS提供恢復(fù)機(jī)制媚值,或多個(gè)連接之間共享相同的協(xié)商密鑰數(shù)據(jù)狠毯。
傳輸層安全(TLS)
會(huì)話標(biāo)識(shí)
“會(huì)話標(biāo)識(shí)符”(RFC 5246)恢復(fù)機(jī)制在SSL 2.0中首次被引入护糖,它允許服務(wù)器在“ServerHello消息”中構(gòu)建和發(fā)送一個(gè)32字節(jié)的會(huì)話標(biāo)識(shí)符褥芒,作為“ServerHello”消息的一部分。
在服務(wù)器內(nèi)部嫡良,服務(wù)器維護(hù)一個(gè)會(huì)話ID和其對(duì)應(yīng)的協(xié)商參數(shù)的緩存锰扶。反過來,客戶端也同時(shí)存儲(chǔ)會(huì)話ID信息寝受,在后續(xù)的會(huì)話中坷牛,可以在“ClientHello”消息中攜帶session ID信息,指示服務(wù)器它保存了session ID對(duì)應(yīng)的密鑰和加密算法等信息很澄,并且可以重用這些信息京闰。假設(shè)在客戶端和服務(wù)器都能在它們各自的緩存中找到共享的會(huì)話ID參數(shù)颜及,那么縮減的握手就可以進(jìn)行了。否則蹂楣,開始一個(gè)新的會(huì)話協(xié)商俏站,這將產(chǎn)生一個(gè)新的會(huì)話ID。
我們演示一下痊土,在前面抓包的的基礎(chǔ)上肄扎,我們?cè)侔l(fā)一次請(qǐng)求。
最外面的紅框顯示了整個(gè)https訪問流程赁酝,內(nèi)部的框是除去TCP握手和分手的的流程犯祠。我們將流程形象畫出來:
借助會(huì)話標(biāo)識(shí)符,我們能夠減少一個(gè)完整的往返酌呆,以及用于協(xié)商的共享密鑰的公鑰加密算法開銷衡载。這讓我們能快速的建立安全連接,而不損失安全性隙袁。我們看一下這個(gè)會(huì)話標(biāo)識(shí):
第二次的請(qǐng)求中的Client Hello的消息中Session Ticket有值了月劈。
那這個(gè)Session Ticket是啥時(shí)候獲取的呢。我們繼續(xù)重溫下https握手流程藤乙,在最后一部猜揪。Server最后發(fā)給Client中,第一個(gè)消息就是New Session Ticket坛梁。我們看一下:
在實(shí)際應(yīng)用中而姐,大多數(shù)Web應(yīng)用程序試圖通過建立到同一個(gè)主機(jī)的多個(gè)連接并行獲取資源,這使得會(huì)話恢復(fù)成為必不可少的一個(gè)優(yōu)化項(xiàng)划咐,其可以減少延??遲拴念,計(jì)算成本。
大多數(shù)現(xiàn)代瀏覽器都會(huì)有意的等待第一TLS連接完成后褐缠,再打開到同一臺(tái)服務(wù)器的新連接:后續(xù)TLS連接政鼠,可以重復(fù)使用的SSL會(huì)話參數(shù),以避免握手的延遲和損耗队魏。
然而公般,“會(huì)話標(biāo)識(shí)符”機(jī)制的一個(gè)限制就是要求服務(wù)器為每個(gè)客戶端創(chuàng)建和維護(hù)一個(gè)會(huì)話緩存。這會(huì)為服務(wù)器上帶來幾個(gè)問題胡桨,對(duì)于一些每天同時(shí)幾萬官帘,甚至幾百萬的單獨(dú)連接的服務(wù)器來說:由于緩存session ID所需要的內(nèi)存消耗將非常大,同時(shí)還有session ID清除策略的問題昧谊。這對(duì)一些流量大的網(wǎng)站來說不是一個(gè)簡(jiǎn)單的任務(wù)刽虹,理想的情況下,使用一個(gè)共享的TLS會(huì)話緩存可以獲得最佳性能呢诬。
上述問題沒有是不可能解決的涌哲,許多高流量的網(wǎng)站成功的使用了會(huì)話標(biāo)識(shí)符胖缤。但是,對(duì)任何多服務(wù)主機(jī)的部署阀圾,會(huì)話標(biāo)識(shí)符方案需要一些認(rèn)真的思考和好的系統(tǒng)架構(gòu)草姻,以確保良好的的會(huì)話緩存。
Session Tickets
為了解決上面的會(huì)話緩存帶來的服務(wù)器部署問題稍刀,“Sesion Ticket”(RFC 5077)取代機(jī)制被引入撩独,目標(biāo)是消除服務(wù)器需要維護(hù)每個(gè)客戶端的會(huì)話狀態(tài)緩存的要求。相反账月,如果客戶指示它支持Session Ticket综膀,在TLS握手的最后一步中服務(wù)器將包含一個(gè)“New Session Ticket”信息,包含了一個(gè)加密通信所需要的信息局齿,這些數(shù)據(jù)采用一個(gè)只有服務(wù)器知道的密鑰進(jìn)行加密剧劝。
這個(gè)Session Ticket由客戶端進(jìn)行存儲(chǔ),并可以在隨后的一次會(huì)話中添加到 ClientHello消息的SessionTicket擴(kuò)展中-因此抓歼,所有的會(huì)話信息只存儲(chǔ)在客戶端上讥此,Session Ticket仍然是安全的,因?yàn)樗怯芍挥蟹?wù)器知道的密鑰加密的谣妻。
Session Identifiers和Session Ticket機(jī)制通常分別被稱為“會(huì)話緩存”和“無狀態(tài)恢復(fù)”機(jī)制萄喳。無狀態(tài)恢復(fù)的主要改進(jìn)是消除服務(wù)器端的會(huì)話緩存,從而簡(jiǎn)化了部署蹋半,它要求客戶在每一個(gè)新的會(huì)話開始時(shí)提供Session Ticket 直到Ticket過期他巨。
在實(shí)際應(yīng)用中,在一組負(fù)載平衡服務(wù)器中部署Session Ticket减江,也需要仔細(xì)考慮:所有的服務(wù)器都必須用相同的會(huì)話密鑰染突,或者可能需要額外的機(jī)制,定期輪流在所有服務(wù)器上的共享密鑰辈灼。
SessionId和Session Ticket的區(qū)別
Session ID的思想就是服務(wù)器端為每一次的會(huì)話生成并記錄一個(gè)ID號(hào)并發(fā)送給客戶端份企,在重新連接的時(shí)候(多次短連接場(chǎng)景),客戶端向服務(wù)器發(fā)送該ID號(hào)巡莹,服務(wù)器查找自己的會(huì)話記錄司志,匹配之后,重用之前的加密參數(shù)信息榕莺。
而Sessionticket的思想類似于cookie俐芯,是由服務(wù)器將ticket數(shù)據(jù)結(jié)構(gòu)發(fā)由客戶端管理,ticket中是包含了加密參數(shù)等連接信息钉鸯。當(dāng)需要重連的時(shí)候,客戶端將ticket發(fā)送給服務(wù)器邮辽。這樣雙方就得到了重用的加密參數(shù)唠雕。
Session ticket較之Session ID優(yōu)勢(shì)在于服務(wù)器使用了負(fù)載均衡等技術(shù)的時(shí)候贸营。Session ID往往是存儲(chǔ)在一臺(tái)服務(wù)器上,當(dāng)我向不同的服務(wù)器請(qǐng)求的時(shí)候岩睁,就無法復(fù)用之前的加密參數(shù)信息钞脂,而Session ticket可以較好的解決此類問題,因?yàn)橄嚓P(guān)的加密參數(shù)信息交由客戶端管理捕儒,服務(wù)器只要確認(rèn)即可冰啃。
證書
證書種類
證書格式
一般來說,主流的 Web 服務(wù)軟件刘莹,通常都基于 OpenSSL 和 Java 兩種基礎(chǔ)密碼庫(kù)阎毅。
Tomcat、Weblogic点弯、JBoss 等 Web 服務(wù)軟件扇调,一般使用 Java 提供的密碼庫(kù)。通過 Java Development Kit (JDK)工具包中的 Keytool 工具抢肛,生成 Java Keystore(JKS)格式的證書文件狼钮。
Apache、Nginx 等 Web 服務(wù)軟件捡絮,一般使用 OpenSSL 工具提供的密碼庫(kù)熬芜,生成 PEM、KEY福稳、CRT 等格式的證書文件猛蔽。
IBM 的 Web 服務(wù)產(chǎn)品,如 Websphere灵寺、IBM Http Server(IHS)等曼库,一般使用 IBM 產(chǎn)品自帶的 iKeyman 工具,生成 KDB 格式的證書文件略板。
微軟 Windows Server 中的 Internet Information Services(IIS)服務(wù)毁枯,使用 Windows 自帶的證書庫(kù)生成 PFX 格式的證書文件。
證書類型
您可以使用以下方法簡(jiǎn)單區(qū)分帶有后綴擴(kuò)展名的證書文件:
- *.DER 或 *.CER 文件: 這樣的證書文件是二進(jìn)制格式叮称,只含有證書信息种玛,不包含私鑰。
- *.CRT 文件: 這樣的證書文件可以是二進(jìn)制格式瓤檐,也可以是文本格式赂韵,一般均為文本格式,功能與 *.DER 及 *.CER 證書文件相同挠蛉。
- *.PEM 文件: 這樣的證書文件一般是文本格式祭示,可以存放證書或私鑰,或者兩者都包含谴古。 *.PEM 文件如果只包含私鑰质涛,一般用 *.KEY 文件代替稠歉。
- *.PFX 或 *.P12 文件: 這樣的證書文件是二進(jìn)制格式,同時(shí)包含證書和私鑰汇陆,且一般有密碼保護(hù)怒炸。
您也可以使用記事本直接打開證書文件。如果顯示的是規(guī)則的數(shù)字字母毡代,例如:
—–BEGIN CERTIFICATE—–
MIIE5zCCA8+gAwIBAgIQN+whYc2BgzAogau0dc3PtzANBgkqh......
—–END CERTIFICATE—–
那么阅羹,該證書文件是文本格式的。
如果存在——BEGIN CERTIFICATE——教寂,則說明這是一個(gè)證書文件捏鱼。
如果存在—–BEGIN RSA PRIVATE KEY—–,則說明這是一個(gè)私鑰文件孝宗。
更多內(nèi)容參考主流數(shù)字證書都有哪些格式穷躁?
常見加密算法
- 非對(duì)稱加密算法:RSA,DSA/DSS
- 對(duì)稱加密算法:AES因妇,RC4问潭,3DES
- HASH算法:MD5,SHA1婚被,SHA256
為啥數(shù)據(jù)傳輸時(shí)候用對(duì)稱加密狡忙?
RSA性能是非常低的,原因在于尋找大素?cái)?shù)址芯、大數(shù)計(jì)算灾茁、數(shù)據(jù)分割需要耗費(fèi)很多的CPU周期,所以一般的HTTPS連接只在第一次握手時(shí)使用非對(duì)稱加密谷炸,通過握手交換對(duì)稱加密密鑰北专,在之后的通信走對(duì)稱加密。