【CSDN有獎組稿】科技之路,共同進步,高品質(zhì)移動發(fā)展,VR/AR/MR,物聯(lián)網(wǎng)原創(chuàng)文章。請給mobilehub@csdn.net發(fā)一封電子郵件。
HTTPS協(xié)議原理分析 HTTPS協(xié)議需要解決的問題HTTPS作為一個安全協(xié)議而誕生,因此它必須面對以下兩個主要的安全問題:
認證
保證雙方身份的真實性。說白了,A想和B溝通,A如何確認B的身份不是C偽造的?
通信加密
通信的保密性和完整性取決于算法和密鑰,以及雙方如何選擇算法和密鑰。
如果能同時解決以上兩個問題,就能保證真實有效的通信方采用有效的算法與密鑰進行通信,進而完成協(xié)議安全的初衷。
在介紹HTTPS協(xié)議如何解決兩個主要安全問題之前,我們首先了解幾個概念。
數(shù)字證書
數(shù)字證書是在互聯(lián)網(wǎng)通信中識別雙方身份信息的數(shù)字文件,由認證機構(gòu)頒發(fā)。
加利福尼亞
證書頒發(fā)機構(gòu)是數(shù)字證書的頒發(fā)機構(gòu)。作為權(quán)威機構(gòu),它在審查申請人的身份后簽發(fā)數(shù)字證書,這樣我們只需要驗證數(shù)字證書就可以確定對方的真實身份。
HTTPS協(xié)議、SSL協(xié)議、TLS協(xié)議和握手協(xié)議的關(guān)系
HTTPS是安全套接層上超文本傳輸協(xié)議的簡稱,即SSL上的HTTP,可以理解為基于SSL的HTTP協(xié)議。HTTPS協(xié)議的安全性是通過SSL協(xié)議實現(xiàn)的(目前常用的,本文以TLS 1.2為基礎(chǔ)進行分析)。
SSL協(xié)議是一種記錄協(xié)議,具有良好的可擴展性,可以輕松添加子協(xié)議,握手協(xié)議是SSL協(xié)議的子協(xié)議。
TLS協(xié)議是SSL協(xié)議的后續(xù)版本,本文涉及的SSL協(xié)議默認為TLS協(xié)議1.2版。
HTTPS協(xié)議的安全性是通過SSL協(xié)議實現(xiàn)的,目前的TLS協(xié)議1.2版包含四個核心子協(xié)議:握手協(xié)議、密鑰配置切換協(xié)議、應(yīng)用數(shù)據(jù)協(xié)議和告警協(xié)議。
握手協(xié)議是認證和通信加密的核心。接下來,著重介紹握手協(xié)議。
信號交換協(xié)議
握手協(xié)議的作用是確認雙方身份,協(xié)商安全連接的參數(shù)(加密算法、密鑰等)。),從而保證雙方的真實身份,協(xié)商的算法和密鑰可以保證通信安全。
握手協(xié)議的引入僅限于客戶端-服務(wù)器認證,單向認證也是互聯(lián)網(wǎng)公司最常用的認證方式。
首先,讓我們看看協(xié)議交互,如圖1所示:
圖1握手協(xié)議
接下來,以Wireshark抓取接口的握手協(xié)議流程為例,分析每個協(xié)議消息。
ClientHello消息
ClientHello消息的作用是一次性向服務(wù)器發(fā)送客戶端可以用來建立加密通道的參數(shù)集。
消息內(nèi)容包括預(yù)期的協(xié)議版本(TLS 1.2)、可用的密碼套件、客戶端隨機數(shù)、擴展和其他信息,如圖2所示。
圖2客戶端您好
服務(wù)器你好消息
服務(wù)器Hello消息的功能是從客戶機Hello參數(shù)集中選擇適當(dāng)?shù)膮?shù),并將服務(wù)器用來建立加密通道的參數(shù)發(fā)送給客戶機。
消息內(nèi)容包括:采用的協(xié)議版本(TLS 1.2)、采用的密碼套件、服務(wù)器隨機數(shù)、會話標(biāo)識(用于恢復(fù)會話的會話標(biāo)識)、擴展字段,如圖3所示。
從那時起,客戶端和服務(wù)器之間的協(xié)議版本和密碼套件就已經(jīng)協(xié)商好了。
這里,服務(wù)器發(fā)出的會話ID可以用于后續(xù)的會話恢復(fù)。如果客戶端在ClientHello中攜帶會話ID,并且服務(wù)器批準,則雙方可以通過原主密鑰直接生成新的一組密鑰繼續(xù)通信。將兩次網(wǎng)絡(luò)往返減少到一次網(wǎng)絡(luò)往返,提高渠道建立效率。
圖3服務(wù)器你好
證書消息
證書消息的目的是向客戶端發(fā)送服務(wù)器證書的詳細信息,以便客戶端驗證服務(wù)器身份。
消息內(nèi)容:服務(wù)器頒發(fā)的證書鏈,如圖4所示。
為了保證客戶端能夠正確識別出頒發(fā)的證書,服務(wù)器需要將頒發(fā)該證書的CA證書一起頒發(fā),形成證書鏈,保證客戶端能夠根據(jù)證書鏈的信息在系統(tǒng)配置中找到根證書,并通過根證書的公鑰逐層驗證證書的有效性。
如圖,58服務(wù)器頒發(fā)了兩個證書:自己的證書和頒發(fā)CA的證書。通過頒發(fā)CA的證書信息,可以直接找到根證書。
圖4證書
客戶端在本地驗證服務(wù)器證書。如果驗證通過,客戶端到服務(wù)器的身份驗證就完成了。
證書解決了兩端的認證問題。有了CA的權(quán)力,證書由CA頒發(fā),認證交給CA。
只要是我們認可的CA,我們都認可證書持有人的身份。由于CA的介入,解決了中間人攻擊的問題,因為中間人沒有服務(wù)器的證書供客戶端驗證。
服務(wù)器密鑰交換消息(可能無法發(fā)送)
服務(wù)器密鑰交換消息的功能是將服務(wù)器提供的密鑰交換的額外參數(shù)發(fā)送給客戶端。有些算法不需要額外的參數(shù),所以服務(wù)器密鑰交換消息可能不會發(fā)送。
消息內(nèi)容:密鑰交換的附加參數(shù),如圖5所示。
圖5服務(wù)器密鑰交換
如圖5所示,服務(wù)器發(fā)出“EC Diffile-Hellman”密鑰交換算法所需的參數(shù)。
服務(wù)器錯誤消息
ServerHelloDone消息的目的是通知客戶端服務(wù)器hello階段的數(shù)據(jù)已經(jīng)發(fā)送,等待客戶端的下一條消息。
ClientKeyExchange消息
客戶機密鑰交換消息的目的是向服務(wù)器發(fā)送客戶機提供密鑰交換所需的數(shù)據(jù)。
當(dāng)我們選擇RSA密鑰交換算法時,該消息的內(nèi)容是由證書的公鑰加密并用于生成主密鑰的預(yù)主密鑰。
如圖6所示,因為選擇的密鑰交換算法是“EC Diffie-Hellman”,所以ClientKeyExchange消息發(fā)送“EC Diffie-Hellman”算法所需的客戶端參數(shù)。
圖6客戶端密鑰交換
客戶端密鑰交換發(fā)送時,兩端都有完整的密鑰數(shù)據(jù)和隨機數(shù)生成主密鑰,兩端都可以根據(jù)選擇的算法計算主密鑰。
至此,ClientKeyExchange發(fā)送后,兩端都可以生成主密鑰,解決了密鑰交換問題。
有些讀者可能對隨機數(shù)的使用有些懷疑。作者認為加入隨機數(shù)是為了提高密鑰的隨機性。
因為客戶端直接生成的密鑰很可能不夠隨機,所以通過使用預(yù)主密鑰加上兩端提供的兩個隨機數(shù)作為種子,可以保證創(chuàng)建的主密鑰更接近真實的隨機密鑰。
更改密碼規(guī)格消息
經(jīng)過以上六條消息,我們解決了身份認證、密碼組選擇和密鑰交換等問題。雙方還通過主密鑰生成了六個實際使用的加密和解密密鑰。
ChangeCipherSpec消息的功能是聲明所有后續(xù)消息都是用密鑰加密的。這條消息之后,我們就看不到WireShark上的明文信息了。
已完成的消息
Finished message的作用是計算握手階段所有消息的匯總,并發(fā)送給對方驗證,避免在通信過程中被中間人篡改。
HTTPS議定書概要
從那時起,我們就知道HTTPS如何通過引入握手協(xié)議來確保通信安全。
然而,在充分利用HTTPS之前,我們還需要考慮一個眾所周知的問題——HTTPS的表現(xiàn)。
與HTTP協(xié)議相比,HTTPS協(xié)議建立數(shù)據(jù)通道更加耗時。如果直接部署在App中,必然會降低數(shù)據(jù)傳輸效率,間接影響用戶體驗。
接下來,我們介紹HTTPS性能拯救者——HTTP 2協(xié)議。
協(xié)議新寵HTTP 2協(xié)議介紹
隨著互聯(lián)網(wǎng)的飛速發(fā)展,HTTP1.x協(xié)議發(fā)展迅速,但是當(dāng)一個App頁面包含幾十個請求時,HTTP1.x協(xié)議的局限性就暴露出來了:
每個請求和響應(yīng)都需要建立一個單獨的鏈接來發(fā)出請求(連接字段可以解決一些問題),這就浪費了資源。
每個請求和響應(yīng)都需要添加完整的報頭信息,應(yīng)用數(shù)據(jù)傳輸效率低。
默認不加密,數(shù)據(jù)在傳輸過程中容易被監(jiān)控和篡改。
HTTP2就是為了解決HTTP1.x暴露的問題而誕生的
說到HTTP2,不得不提spdy。
由于HTTP1.x暴露的問題,Google設(shè)計了一個新的協(xié)議,叫做spdy。Spdy在五層協(xié)議棧的TCP層和HTTP層引入了新的邏輯層,提高了效率。Spdy是中間層,兼容TCP層和HTTP層,在不修改HTTP層的情況下,可以提高應(yīng)用數(shù)據(jù)傳輸速度。
通過復(fù)用技術(shù),spdy使客戶端和服務(wù)器能夠多次交互,提高了通信效率。
而HTTP2是基于spdy開發(fā)的。
通過引入流和幀的概念,繼承了spdy的復(fù)用性,并增加了一些實用特性。
HTTP2有什么特點?HTTP2的特性不僅解決了上述暴露的問題,還具有一些使HTTP協(xié)議更加有用的功能。
多路技術(shù)
壓縮標(biāo)題信息
優(yōu)先處理請求
支持服務(wù)器向客戶端推送消息
另外,目前HTTP2只在HTTPS協(xié)議場景中使用,在握手階段通過ClientHello和ServerHello的擴展字段協(xié)商,所以目前HTTP2的使用場景默認都是安全加密的。
下面描述HTTP2協(xié)議協(xié)商的兩個特點,復(fù)用和報頭信息壓縮。實現(xiàn)部分利用okhttp源代碼(基于parent-3.4.2)進行分析介紹。
okhttp是目前使用最廣泛的支持HTTP2的Android開源網(wǎng)絡(luò)庫。以okhttp為例介紹HTTP2特性,也可以方便讀者提前了解okhttp,以后訪問okhttp。
協(xié)議協(xié)商HTTP2協(xié)議的協(xié)商在握手階段進行。
協(xié)商的方式是擴展握手協(xié)議擴展字段,增加一個應(yīng)用層協(xié)議協(xié)商字段進行協(xié)商。
在握手協(xié)議的客戶機Hello階段,客戶機在應(yīng)用層協(xié)議協(xié)商字段中填寫支持的協(xié)議列表,供服務(wù)器選擇。如圖7所示:
圖7 ALPN1
收到ClientHello消息后,服務(wù)器從客戶端支持的協(xié)議列表中選擇適當(dāng)?shù)膮f(xié)議作為后續(xù)的應(yīng)用層協(xié)議。如圖8所示:
圖8 ALPN2
這樣,兩端都完成了HTTP2協(xié)議的協(xié)商。
在沒有HTTP2的情況下,spdy還通過擴展字段來擴展next_protocol_negotiation字段,并與NPN協(xié)議協(xié)商spdy。然而,由于NPN協(xié)商的復(fù)雜性,對https協(xié)議的入侵性很強,在ALPN協(xié)商協(xié)議出現(xiàn)后,逐漸被淘汰。因此,本文討論了協(xié)議協(xié)商,并介紹了NPN協(xié)議的協(xié)商。
協(xié)議特性之多路復(fù)用為了優(yōu)化http1.x對TCP性能的浪費,http2提出了復(fù)用的概念。
復(fù)用的意義
在HTTP2中,同一個域名下的請求可以通過同一個TCP鏈路傳輸,這樣多個請求就不需要獨立建立鏈路,節(jié)省了建立鏈路的開銷。
為了達到這個目的,HTTP2提出了流和框架的概念。流表示請求和響應(yīng),而請求和響應(yīng)的具體數(shù)據(jù)被打包成幀。鏈路中傳輸?shù)臄?shù)據(jù)根據(jù)流標(biāo)識和幀類型進行不同的處理。圖9是復(fù)用的抽象圖,其中每個塊代表一個幀,而相同顏色的塊代表相同的流。
圖9 http2_stream
那么HTTP2復(fù)用是如何實現(xiàn)的呢?
由于有許多網(wǎng)絡(luò)請求的場景,我們選擇其中一個路徑來介紹:
已經(jīng)在域名中的客戶端和服務(wù)器之間建立了一個TCP通道
新創(chuàng)建的客戶端請求通過連接的TCP通道發(fā)送和響應(yīng)
多路復(fù)用實現(xiàn)
默認情況下,我們添加了各種參數(shù)來創(chuàng)建請求對象R,并通過請求對象創(chuàng)建了調(diào)用對象C。在獨立線程中,調(diào)用c.execute()方法執(zhí)行同步請求操作。
okhttp調(diào)用execute方法后,實際上是由一系列的攔截器執(zhí)行的。
攔截器是按照添加的順序執(zhí)行的,其中我們關(guān)注的是RetryAndFollowUpInterceptor、ConnectInterceptor0和CallServerInterceptor。
1.在RetryAndFollowUpInterceptor中,okhttp為我們創(chuàng)建了一個StreamAllocation對象,其中包含一個基于url創(chuàng)建的Address對象。
地址類的url字段不同于請求類的URL字段。Address類的url字段不包含路徑和查詢字段,只包含方案和權(quán)限,這在Connection復(fù)用的平等操作中起著很大的作用。
2.在連接攔截器中,流分配對象的地址依次與連接池中每個連接對象的地址相匹配,匹配成功并滿足某些條件的連接可以被重用?;谄ヅ涞倪B接為后續(xù)的讀寫操作創(chuàng)建Http2xStream。
連接池中與Address的匹配主要是通過Address的url,url因為只包含方案和權(quán)限,所以可以用于域名匹配,這是基于域名級別的okhttp復(fù)用的基礎(chǔ)。
其實真正的流讀寫操作是FramedConnection和FramedStream,Connection和Http2xStream是為了方便上層而從具體操作中抽象出來的類。
3.在CallServerInterceptor中,Http2xStream為請求發(fā)送創(chuàng)建一個FrameStream,用對應(yīng)的StreamID緩存FrameStream綁定,這樣在響應(yīng)到來時,就可以根據(jù)StreamID索引來跟進操作。
在FramedStream發(fā)送請求后,執(zhí)行readResponseHeaders方法時調(diào)用等待,當(dāng)前線程被掛起。
當(dāng)幀連接讀取線程接收到流標(biāo)識消息時,它會查詢緩存中的幀流,并喚醒相應(yīng)的線程進行響應(yīng)解碼。
總結(jié)okhttp的復(fù)用實現(xiàn)思路:
通過將請求的地址與連接池中現(xiàn)有的連接地址進行匹配,選擇可用的連接。
由Http2xStream創(chuàng)建的FramedStream在發(fā)送請求后緩存FramedConnection中FramedStream對象和StreamID之間的映射關(guān)系。
收到消息后,幀連接解析幀信息,通過解析的流標(biāo)識從映射中選擇緩存的幀流,并喚醒幀流來處理響應(yīng)。
在我看來,http2是一種與http協(xié)議格式兼容的自定義協(xié)議,通過Stream向請求分發(fā)數(shù)據(jù),通過Frame對請求數(shù)據(jù)進行詳細細分。
協(xié)議特性之壓縮頭信息為了解決HTTP1.x中報頭信息過多導(dǎo)致效率低下的問題,HTTP2提出的解決方案是壓縮報頭信息。在具體的壓縮模式中,引入了HPACK。
HPACK壓縮算法專用于HTTP2報頭壓縮。為了壓縮報頭信息,HPACK緩存報頭字段作為索引,索引ID代表報頭字段??蛻舳撕头?wù)器端維護索引表,在通信過程中盡量使用索引進行通信,收到索引后查詢索引表,從而分析出真實的表頭信息。
HPACK索引表分為動態(tài)索引表和靜態(tài)索引表。動態(tài)索引表是HTTP2協(xié)議通信時兩端動態(tài)維護的索引表,靜態(tài)索引表是硬編碼到協(xié)議中的索引表。
作為分析H-pack壓縮頭信息的基礎(chǔ),有必要介紹H-pack如何表示索引和頭字符串。
指數(shù)
索引用整數(shù)表示。由于HPACK需要考慮壓縮、編碼和解碼,整數(shù)的結(jié)構(gòu)定義如圖10所示。
圖10內(nèi)部支柱
類別id
HPACK分類是通過類別識別來指導(dǎo)后續(xù)的編解碼操作,共有1,010,100,000,000等八個常見類別。
第一個字節(jié)低整數(shù)
第一個字節(jié)不包括類別標(biāo)識符的剩余位,后者用于指示較低的整數(shù)。如果該值大于剩余位表示的容量,則需要后續(xù)字節(jié)來表示高整數(shù)。
結(jié)束id
指示該字節(jié)是否為整數(shù)解析終止字節(jié)。
高整數(shù)
字節(jié)的剩余7位用于填充高整數(shù)位。
根據(jù)數(shù)據(jù)大小,可能有0個或更多“結(jié)束標(biāo)識+高整數(shù)”字節(jié)。
例如,如果您想指示類為1,索引為2,可以使用10000010,并且不需要額外的字節(jié)來增加高整數(shù)。
標(biāo)題字符串
頭串的長度需要顯式聲明,所以數(shù)據(jù)的第一個字節(jié)由“類型標(biāo)識符+數(shù)據(jù)長度”組成。如圖11所示:
圖11弦_支柱
類型id
是否選擇霍夫曼編碼,選擇1,不選擇0,okhttp默認不選擇霍夫曼編碼。
數(shù)據(jù)長度
標(biāo)識數(shù)據(jù)長度,用上面提到的整數(shù)表示法表示。
數(shù)據(jù)內(nèi)容
二進制數(shù)據(jù)。
解碼示例
下面全面的okhttp源代碼分析HPACK解碼頭字段的過程。
對編碼感興趣的讀者可以參考RFC 7541或者直接分析OkHttp源代碼。
當(dāng)我們需要解碼報頭字段時,我們首先解析報頭字段的第一個字節(jié)(HPACK報頭字段的第一個字節(jié)分為8個類別,其中選擇了3個類別描述),第一個字節(jié)用于指導(dǎo)當(dāng)前報頭字段的解析規(guī)則:
1xxxxxxx
類id為1,這意味著接收到一個以k和v為索引的頭字段。
k,V值:通過解析HPACK整數(shù)得到KV對的索引值,根據(jù)索引值映射對應(yīng)的頭原字段,壓縮效率最高。
01xxxxxx
類別ID為01,表示接收到以K為索引、V為原始字段的表頭字段,需要添加到動態(tài)索引表中。
k值:k值的索引值是通過解析HPACK整數(shù)得到的,對應(yīng)的頭原字段由索引值映射。
v值:v值的原始字段是通過解析HPACK字符串得到的。
k和v的值需要插入到動態(tài)索引表中。
01000000
01000000表示k和v都是原始字段,需要添加到動態(tài)索引表的表頭字段。
k和v值:k和v的原始字段通過解析HPACK字符串得到,并插入到動態(tài)索引表中。
有不添加動態(tài)索引表、調(diào)整索引表大小等類別,這里不展開。如果有興趣,可以看看okhttp源代碼的實現(xiàn)。
okhttp解析頭信息的核心方法實現(xiàn)如下:
voidreadHeaders()引發(fā)IOException {
while(!source . excluded()){ int b = source . read byte()& amp;0xff
if(b = = 0x 80){//10000000//類別ID為1,但索引為0 0 throwenwioeexception(" index = = 0 ");} else if((b & amp;0x 80)= = 0x 80){//1 nnnnnn//類別為1,整數(shù)索引通過readIndexedHeader解析。int index = ReadNT(b,PREFX _ 7 _ BITS);
//通過index獲取完整的表頭字段readIndexedHeader(index-1);} else if(b = = 0x 40){//01000000//0100000表示KV為原字段。對字符串進行分析,依次得到k值和v值,插入到動態(tài)表read literatureheaderwith incrementalidenxignewname();} else if((b & amp;0x 40)= = 0x 40){//01 nnnnnn//01 xxxxx代表k值作為索引,v值作為原始字符串。依次解析整數(shù)索引和字符串,在動態(tài)表中插入int index = readint (b,prefix _ 6 _ bits);readliteralheaderwrithincrementalindexingindexed name(index-1);} else if((b & amp;0x 20)= = 0x 20){//001 nnnn//類別為001,表示更新動態(tài)列表容量maxdynamictablebytecount = readint(b,prefix _ 5 _ bits
if(MaxDynamiCTableByteCount & lt;0 | | MaxDynamiCTableByteCount & gt;headeratableizesetting){
thrownewIOException("無效動態(tài)表大小更新"+maxDynamicTableByteCount);} adjustDynamicTableByteCount();} elseif(b == 0x10|| b == 0) { // 000?0000-忽略從不索引位。//此類別表示KV為原始字符串,字符串依次解析,解析后的KV值不插入動態(tài)表。readLiteralHeaderWithoutIndexingNewName();} else{ // 000?NNNN-忽略從不索引位。//類似于前一類,但是k是索引,v是原字符串int index = readint (b,prefix _ 4 _ bits);readliteralheadrwithoutindexingindexed name(index-1);} }}
壓縮效應(yīng)
k值為“accept-encoding”v值為“g,deflate”的頭字段,在HTTP2中可以用索引值15代替,從而達到頭字段壓縮的效果。
“accept-charset”報頭字段用14表示報頭k值,該值根據(jù)HPACK規(guī)則被編碼并寫入流中。
有了HPACK,一個報頭字段變化少的App,會把每個報頭字段壓縮到4字節(jié)以下,壓縮效果非常明顯。
1.《http2 HTTPS 與 HTTP2 協(xié)議分析》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識,僅代表作者本人觀點,與本網(wǎng)站無關(guān),侵刪請聯(lián)系頁腳下方聯(lián)系方式。
2.《http2 HTTPS 與 HTTP2 協(xié)議分析》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進行證實,對其原創(chuàng)性、真實性、完整性、及時性不作任何保證。
3.文章轉(zhuǎn)載時請保留本站內(nèi)容來源地址,http://f99ss.com/guonei/796758.html