Http與Https協議

謎一樣的Coder發表於2018-08-05

前言

這兩個協議,在分散式通訊過程中最為常用,面試中出現頻率也是最多的,但是一直沒有實際總結過,今天對其進行一個總結。

這裡打算基於Fiddler工具,進行HTTP抓包分析,fiddler使用教程如下:fiddler使用教程

簡介

HTTP協議相對來說容易一點,也是比較好理解的一個協議,本身是應用層協議,但是因為HTTP協議本身的一些問題,延伸出來的一些解決方案值得深入的學習,例如HTTP本身是無狀態的協議,針對HTTP本身的無狀態問題,有著相應的解決方式(增加session),這裡也會做出相應的總結。

URL與URI

其實單獨提出這兩個的概念顯得有點多餘,但是這裡還是提一下,總的一句就可以區別,URL是URI的子集,如果說URL表示一個人的名片的話,那麼URI表示了這個人的名片資訊+地址資訊。下面一張圖簡單看一下就可以。

HTTP請求報文

fiddler中抓包的HTTP請求報文如下所示:

HTTP請求報文分為三個部分:1.請求行,2.報文頭,3.報文體。

請求行

例項:GET http://www.baidu.com HTTP/1.1

請求行以方法名開頭,後面跟著URI和HTTP協議版本,中間通過空格隔開,後面兩個沒什麼好介紹的,這裡主要說明一下方法,通過下面一張表格可以總結出來

HTTP請求報文支援的方法
方法 說明 支援的HTTP協議
GET 獲取資源 1.0、1.1
POST 傳輸實體主體(客戶端要告知伺服器某條訊息) 1.0、1.1
PUT 傳輸檔案 1.0、1.1
HEAD 用於確認URI的有效性及資源更新的日期 1.0、1.1
DELETE 刪除檔案,與PUT相反 1.0、1.1
OPTIONS 查詢請求URI指定的資源(伺服器)所支援的方法 1.1
TRACE 讓伺服器將之前的請求通訊環回給客戶端 1.1
CONNECT 要求用隧道協議連線代理(暫時理解不深入) 1.1
LINK 建立和資源之間的聯絡 1.0
UNLINK 斷開連線關係 1.0

其中最為熟悉的可能就是GET和POST請求,這個兩個請求是開發中最為常用的兩種,GET與POST的區別,這裡也不在贅述,可以參考相關的部落格——GET與POST區別

請求報文頭後面將會和響應報文頭一塊進行總結,這裡暫時不描述,針對請求報文體,一般可以理解為傳送給伺服器的引數,根據方法的不同,引數不一樣,請求報文體也就不一樣。

HTTP響應報文

響應報文例項:

HTTP響應報文大體結構和請求報文結構區別不大,主要也是三個結構:1、狀態行,2、各種首部欄位,3、報文主體。

狀態行比較簡單,也是由三個部分組成:協議版本,狀態碼和狀態碼的文字描述(CRLF)。一些狀態碼能代表一些資訊,而且在實際開發中,有時候會利用狀態碼進行進行相關資訊的判斷,這裡針對響應狀態碼做一個表格總結

HTTP響應狀態碼

狀態碼的類別(大類)
  類別 簡單描述
1XX Information(資訊狀態碼) 接收的請求正在處理
2XX Success(成功狀態碼) 請求正常處理完畢
3XX Redirection(重定向狀態碼) 需要進行俯角操作以完成請求
4XX Client Error(客戶端錯誤狀態碼) 伺服器無法處理請求
5XX Server Error(伺服器錯誤狀態碼) 伺服器處理請求出錯

HTTP狀態響應碼的大類的總結可以參照上面的表格,但是有時候會具體到某個狀態碼的描述,這裡需要進一步總結,1XX開頭的狀態碼幾乎沒怎麼接觸過,這裡不進一步總結1XX的狀態碼。

200 OK 這個可以說是最常見的狀態碼了,表示客戶端請求成功。

204  表示伺服器接收的請求已經成功處理,但在返回的響應報文中不含實體的主體部分(不含有響應報文主體),一般返回204請求之後,瀏覽器顯示的頁面不會發生更新,該響應碼常用於PUT、DELETE請求中。

206 表示客戶端進行了範圍請求(響應報文中包含Content-Range指定範圍的實體內容)。

 

301 永久性重定向,表示客戶端所請求的資源已經被分配了新的URI,這時客戶端需要重新更新儲存的URI

302 臨時性重定向(與301的具體區別後面通過tracert進行探究)。

303 與302作用相同,但是303明確表示客戶端需要採用GET方法獲得資源。

304 表示服務端資源沒有改變,可以使用客戶端中為過期的快取(和重定向關係不大)

307 與302作用相同,只是不會強制要求用GET請求。

 

400 請求報文中存在語法錯誤

401 認證失敗(這裡指的是網頁認證失敗,通常指的就是登入使用者名稱和密碼失敗)

403 未授權訪問該資源

404 這個就不用解釋了——算是我朝國產最流行的動漫之一。

 

500 伺服器端程式出現bug

503 Service Unavailable 伺服器超負荷

HTTP首部欄位(報頭訊息)

上面只是介紹了報文的請求行和狀態行的相關資訊,這裡就詳細介紹各個首部欄位,分為四個部分進行介紹:1、通用首部欄位,2、請求首部欄位,3、響應首部欄位,4、實體首部欄位。

通用首部欄位

顧名思義,指的就是請求報文和響應報文首部都會用到的欄位

通用首部欄位
首部欄位名 說明
Cache-control 控制快取的行為
Connection 逐跳首部、連線的管理
Date 建立報文的日期時間
Pragma 報文指令
Trailer 報文末端的首部一覽
Transfer-Encoding 指定報文主體的傳輸編碼方式
Upgrade 升級為其他協議
Via 代理伺服器的相關資訊
Warning 錯誤通知

Cache-control

例項:Cache-control : private,max-age=0,no-cache

針對快取的處理,其實是一個比較複雜的過程,Cache-control的引數是可選的,多個指令之間通過英文逗號分隔。

Cache-control請求指令
指令 引數 說明
no-cache

強制向伺服器再次驗證(重新快取)。

 

客戶端請求報文中如果有該指令,表示客戶端不會接受快取伺服器的資源。

伺服器端響應報文中如果有該指令,表示快取伺服器不得對該報文內容做快取。

 

該指令只是表示不會快取過期的報文資源,no-store才是真正的不快取。

no-store

不快取請求或響應的任何內容

 

請求或響應中有機密資訊,伺服器和快取伺服器都不得快取報文任何內容。

max-age=[秒] 必需

響應的最大Age值。

 

如果客戶端得知快取資源存在的時間比指定的時間小,那麼客戶端就接收快取資料,否則快取伺服器會去請求源伺服器。

 

如果服務端的響應報文中有這個指令,表示在max-age的時間段內,伺服器不會更新快取資料

 

該欄位優先順序比Expires高。

max-stale=[秒] 非必需

期待在指定時間內的響應扔有效。

 

快取過期後指定的時間內,依舊有效。

min-fresh=[秒] 必需

返回指定數值內會過期的快取資料。

 

min-fresh = 60 表示返回60秒內會過期的快取資料。

no-transform

代理不可更改媒體型別

 

在請求報文和響應報文中,快取都不能改變實體主體的媒體型別。防止快取壓縮圖片或者視訊等

only-if-cached

從快取獲取資源。

客戶端就要用快取資料,並要求快取伺服器不重新載入響應,如果快取的資料沒有響應,則會返回504 Gateway Timeout

cache-extension -

新指令標記。

可以擴充套件Cache-control欄位內的內容,

Connection

這個首部欄位主要具有兩個作用:1、控制不再轉發給代理的首部欄位。2、管理持久連線。

1、控制不再轉發給代理的首部欄位

這個結合例項好理解點

請求報文頭:

GET / HTTP/1.1

Update:HTTP/1.1

Connection:Upgrade

注意這裡請求報文頭Connection欄位,且Connection指定了Update欄位。客戶端報文在傳送給代理伺服器的時候,Update不會出現在代理伺服器中。

2、管理持久連線

HTTP在1.1版本之後都預設持久連線(每次傳輸資料的時候,不用每次通過握手建立TCP/IP連線),當伺服器明確想斷開連線時,則指定Connection首部欄位的值為close。

Date

這個就不用解釋了

Pragma

一個相容性設計,HTTP1.0中的遺留欄位,這裡也不做詳細介紹。

Trailer

我個人理解為報文主題的摘要

Transfer-Encoding

規定傳輸報文主體的編碼方式,所規定的編碼方式只對分塊傳輸編碼有效。

Upgrade

用於指定能否可以用其他的通訊協議,例如Upgrade:TLS/1.0,告知伺服器,客戶端可否使用TLS/1.0通訊協議,但同時還需要配合使用Connection欄位,且Connection欄位需要指定為Upgrade.

Upgrade:TLS/1.0

Connection:Upgrade

上述兩個欄位一起才能起作用,有時候Upgrade指定了新的協議方式之後,伺服器會返回101 Switching Protocols狀態碼

Via

為了追蹤客戶端與伺服器之間的請求和響應報文的傳輸路徑,報文經過代理或者閘道器時,會在報文via欄位中增加本伺服器的資訊,這和traceroute類似

Warning

會告知一些快取伺服器的警告訊息,這裡不詳細討論。詳情參見——HTTP-WRAN

請求首部欄位

從客戶端發往伺服器的請求報文中特有的欄位

名稱 作用 示例
Accept 告知伺服器客戶端能處理的媒體型別

Accept:text/html,application/xhtml+xml,application/xml;q=0.6

 

說明:可以指定多種媒體型別,基本是type(大型別)/subType(子型別)這種形式指定,後面的q是權值的意思,0<q<=1,預設q=1

Accept-Charset 告知伺服器接受的字元型別集合

Accept-Charset:iso-8859-5,unicode-1-1;q=0.8

 

說明:可以一次性指定多個字符集,同時q也為權值,與Accept中的q含義一樣。

Accept-Encoding 告知伺服器支援的檔案編碼型別和檔案編碼的優先順序

Accept-Encoding:gzip,deflate;q=0.2

 

說明:可以一次性指定多個編碼格式,同樣存在q權值

Accept-Language 告知伺服器支援的語言,以及優先順序 Accept-Language:zh-cn,zh;q=0.7,en-us;q=0.3
Authorization 向伺服器傳遞認證資訊 Authroization:Basic dWVub3NlbjpwYXNzd29yZA==
Expect 告知伺服器期望出現的某種特定行為 Except:100-continue
From 告知伺服器,客戶端的郵箱服務地址? From:657271181@qq.com
Host 告知伺服器想要訪問的網際網路主機名稱

Host:www.baidu.com

 

說明:這個欄位必須要揹包含在請求頭首部中

If-Match 指定ETag值

If-Match:"897695"

 

說明:伺服器會對比客戶端通過該欄位帶過來的ETag值,如果相同會返回與ETag相符的資源,如果沒有,則會返回412 Precondition Failed的響應。

If-Modified-Since 告知伺服器,我只要指定日期更新後的資源

If-Modified-Since:Thu, 15 Aug 2018 00:00:00 GMT

 

客戶端只接受2018年8月15號以後更新的資源,如果資源從這之前就沒有更新過了,服務端會給客戶端返回 304 not modified

If-None-Matched 與If-Match的作用正好相反,返回與所指定ETag值不匹配的資源
If-Range 告知伺服器,若指定的if-Range欄位(可以指定時間或ETag)和請求資源的ETag或時間一致,則伺服器會處理請求,如果不一致,服務端會返回全部資源
If-Unmodified-Since 與If-Modified-since相反 If-Unmodified-Since: Thu, 03 Jul 2012 00:00:00 GMT
在欄位指定的日期之後沒有發生更新的情況下才會返回,如果發生了更新,會返回412 Precondition Failed
Max-Forwards 當 Max-Forwards 欄位值為 0 時, 伺服器就會立即返回
響應。
Max-Forwards: 10
每走一步,該數值就減一,到0的時候,直接返回響應
Proxy-Authorization 發生在客戶端與代理伺服器之間的認證 Proxy-Authorization: Basic dGlwOjkpNLAGfFY5
不同於Authorization欄位,這個欄位只是發生在客戶端與代理伺服器之間的認證。
Range 只是獲取伺服器指定範圍的資源

Range: bytes=5001-10000
 

只獲取伺服器第5001直接到10000位元組的內容。

Referer 告知伺服器請求的原始資源的 URI

Referer: http://www.baidu.comindex.htm
 

該請求從http://www.baidu.com/index.htm發起的,這個功能可以用於防盜鏈

TE 告知伺服器客戶端能處理的傳輸編碼(不是位元組編碼和檔案編碼) TE: gzip, deflate;q=0.5
同時也有優先順序欄位。
User-Agent 瀏覽器種類 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0)

上述表格基本都總結了各個請求欄位,每一個欄位都做出了示例說明,一些在實際中用的並不錯,有些需要結合示例進行理解,還有一些不常見的返回碼也會出現在示例中,後續可以詳細探討。

響應首部欄位

服務端向客戶端返回的報文中所使用的欄位。依舊還是以表格的形式進行總結

名稱 作用 示例
Accept-Ranges 告知客戶端伺服器能能否處理範文請求

Accept-Ranges:bytes/none

 

說明:bytes表示伺服器能處理範圍請求,none表示不能。

Age 一般由快取伺服器告知客戶端,伺服器在多久前建立了該響應

Age:600

說明:快取伺服器告知客戶端,源伺服器在10分鐘前建立了該響應。Age屬性值的單位為秒。

ETag 告知客戶端實體標識,當服務端資源更新時,ETag值也會更新 ETag: "82e22293907ce725faf67773957acd12"
說明:參見這篇部落格——ETag詳解
Location 告知客戶端請求的資源在指定的位置,幾乎所有的瀏覽器客戶端在接受到location欄位之後都會強制跳轉,重新發起請求。

Location: http://www.baidu.com/sample.html
 

說明:基本上該欄位會配合3XX:Redirection響應。

Proxy-Authenticate 告知客戶端代理伺服器需要認證 見後面的詳細闡述
Retry-After 告知客戶端在多久之後重新傳送請求。

Retry-After:120

說明:2分鐘之後再次傳送,常配合503和3XX欄位使用

Server 告知客戶端當前的伺服器資訊 Server: Apache/2.2.6 (Unix) PHP/5.2.5
Vary

首部欄位 Vary 可對快取進行控制。 源伺服器會向代理伺服器傳達關於本地快取使用方法的命令。


從代理伺服器接收到源伺服器返回包含 Vary 指定項的響應之後, 若
再要進行快取, 僅對請求中含有相同 Vary 指定首部欄位的請求返回快取。 即使對相同資源發起請求, 但由於 Vary 指定的首部欄位不相同, 因此必須要從源伺服器重新獲取資源。

Vary:Accept-Language

 

相關示例需要參考些許資料,或實際中進一步總結。

WWW-Authenticate 用於HTTP訪問認證 狀態碼 401 Unauthorized 響應中,肯定帶有首部欄位 WWW-Authenticate。

實體首部欄位

實體首部欄位是出現在報文實體中的欄位,這裡的報文實體包括了請求報文實體和響應報文實體。

名稱 作用 例項
Allow 告知對方自己支援的所有HTTP方法

Allow:GET,HEAD

說明:如果伺服器接收到自己不支援的方法,會返回405 Method Not Allowed,這一點在開發中深有體會,有時會在Controller中限制使用post方法,但是利用postman傳送請求的時候卻是get方法,就會丟擲這個錯誤。

Content-Encoding 服務端告知客戶端,響應報文的編碼方式

Content-Encoding:gzip

Content-Language 告知客戶端,實體報文的自然語言 Content-Language:zh-CN
Content-Length 告知對方實體報文的大小 Content-Length:15000
Content-Location 給出報文主體相對應的URI

Content-Location:http://www.baidu.com/index.html

Content-MD5 用於檢查報文主體在傳輸過程中是否儲存完整 基本同上
Content-Range 告知客戶端返回的實體是那個範圍的 Content-Range:bytes 5001-10000/10000
Content-Type 說明實體主體內物件的列舉型別 Content-Type:text/html;charset=UTF-8
Expires 告知客戶端資源失效的日期
Last-Modified 告知客戶端最後的修改日期

與Cookie相關的欄位

與cookie相關的欄位只有兩個,由於Http協議本身是無狀態協議,為了期望儲存客戶端的回話狀態,於是就引入了cookie技術。

在梳理相關欄位之前,還是先理清Cookie與Session的區別,這兩者之前看過N多次,都沒有進行總結和梳理。

1、Cookie是存在客戶端,Session是儲存在服務端。之前為了讓伺服器記住通訊狀態,客戶端在首次訪問伺服器之後的回話過程中會帶上cookie中的內容,使得伺服器能根據cookie資訊判斷客戶端是否已經訪問過。

2、Session是儲存在伺服器端的,用個SessionId來區分每個客戶的session

3、現在比較通用的做法是在cookie中儲存一個sessionId,客戶端在訪問伺服器的時候,帶上sessionId,伺服器根據sessionId獲取之前的回話資訊。

4、如果客戶端禁用了cookie,sessionId會通過url傳送到服務端,這就是為什麼有時候url後面會帶有sessionId引數的原因。

與cookie相關的欄位只有兩個,Set-cookie和Cookie,其中Cookie只是標記本地Cookie是否能用,這個比較簡單,沒什麼可介紹的。Set-cookie中有很多屬性,這些屬性中包括NAME,expires,path,domain,Secure,HttpOnly

NAME——cookie的名字

expires——cookie的有效期

path,domain——指定的路徑或域名下,才傳送cookie

secure——只有在HTTPS的情況下才傳送cookie

HttpOnly——使得JS無法獲取cookie中的內容(document.cookie無效)

==========================================完美的分割線=======================================

 

其實在分散式環境中,Session的同步需要花費相當大的代價,在分散式環境下,通常會用accessToken的方式去解決相關問題。

HTTPS

終於寫到HTTPS了,這就是這篇部落格的重點所在。

HTTP協議本身的問題除了無狀態以外,還有一個最大的問題就是HTTP是明文通訊,安全性是一個大問題。

HTTPS協議本身比較複雜,這裡只是做一個簡單瞭解,參考相關部落格作出自己的總結。這裡的總結目的只是檢驗自己讀懂的大牛的部落格而已,不做更多的要求,各位看官可以直接移步大牛的部落格:HTTPS的通俗解釋

HTTPS理解前需要熟悉的

還記得,大學計算機網路這門課的開篇就會有這樣一個例子,所有的通訊,其實就是為了解決可靠性。最簡單的通訊模式就是下圖所示的模式,A直接傳送訊息給B,但是從某一種程度考慮,B能否確保訊息來源就是A,A能否確保訊息接收端就是B?這就是計算機網路需要解決的問題。大牛的部落格就是從這樣一個簡單的模型開始,進行深入的介紹。

對稱加密傳輸

在上述簡單的通訊模型上建立安全,我們首先想到的就是對Hello這個文字加密,然後A、B雙方用對應的金鑰去解密,這就能保證基本的通訊安全。談到對稱加密並不陌生,常見的有DES、RSA等等。

 這就是簡單的對稱加密模型,其中的金鑰即扮演加密的角色,也扮演解密的角色,只要這個金鑰不被第三個人知道,A和B的通訊就是安全的。這也就是我們常說的對稱加密,加密和解密的金鑰是同一個。

但是,在網際網路背景下,我們的通訊環境可不會只有兩個人。一個Web伺服器請求會有多個使用者訪問,我們的通訊模型不會簡單到這個地步。

如果同時使用一個金鑰,這跟沒加密有和區別,心術不正的人依舊會得到通用的金鑰,很容易篡改相關的資料包文。

 但是由於非對稱加密在通訊過程中會耗費較多伺服器資源,所以,伺服器在與客戶端正式交換資料時依舊採用的是對稱加密的資料傳輸,只是每個請求會採用金鑰協商,真正的金鑰在正式交換報文前才確定下來。如下圖所示:

HTTPS中的非對稱加密

看似沒毛病了,可是另一個問題出來了,如何安全的確定金鑰?換句話說,服務端與客戶端如何安全的進行金鑰協商。這就要用到非對稱加密了。具體非對稱加密的過程這裡不做探討,這個過程依舊很複雜,可以參考《改變世界的九大演算法》一書中的相關章節簡單瞭解。

這裡我們只需要知道非對稱金鑰的特點——私鑰加密後的密文,只要是公鑰,都可以解密,但是公鑰加密後的密文,只有私鑰可以解密。私鑰只有一個人有,而公鑰可以交給任何人。

目前,服務端將公鑰傳送給任何人,客戶端用服務端給的公鑰加密,然後將加密後的資料傳送給服務端,服務端用私鑰解密。(圖是盜的,非常不錯的一張圖.......) 目前至少保證了從客戶端到伺服器端通訊的安全性,但是伺服器端到客戶端的通訊安全依舊沒法保證。於是這就要用到非對稱加密了,總的來說就是利用非對稱加密演算法加密對稱加密演算法的協商過程(有點繞)。

HTTPS中的公鑰、數字證照、數字簽名

如何讓客戶端的到公鑰,這也是個問題。目前主要有兩個方案。第一:伺服器端直接將公鑰傳送給每一個客戶端。第二:服務端將公鑰放到一個遠端伺服器,客戶端可以請求得到。

針對第一種方案,很容易出現公鑰被中間者調包的情況。其實理解到這裡,最重要的就是需要明白,客戶端如何保證接收到的資訊來自伺服器

公鑰這個概念就不用詳細介紹了,為了將公鑰安全的傳遞給客戶端,我們並不能直接將公鑰傳遞給客戶端,而是第三方機構使用其私鑰對伺服器的公鑰加密之後,再傳遞給客戶端。客戶端再使用第三方機構的公鑰進行解密。

所謂的數字證照:就是伺服器將公鑰交給了第三方機構,然後第三方機構用自己的私鑰將其加密後的結果,這個就是數字證照。如果客戶端能夠用第三方機構的公鑰解密,獲得數字證照,就說明這個公鑰沒有被調包過。因為如果中間人調包了這個數字證照,會用自己的私鑰去加密這個證照,然後客戶端用第三方機構的公鑰並不能解密中間人傳送的資料包。

但是還有一個問題,中間人其實也可以去中間機構獲取證照,然後同樣也能完成資料篡改。這個時候,數字簽名就發揮作用了。數字簽名的主要作用就是用於解決同一機構頒發的不同證照被篡改的問題,這個就和我們本身的學位證照上的證照編號作用一樣,HR在入職的時候,會拿著我們的學位證照編號,去學信網(中間機構)查詢我們證照的真偽。

其實,真正的數字簽名的驗證在客戶端本地就完成了。因為證照本身已經告訴了客戶端怎麼去驗證證照的真偽。也就是,客戶端拿到數字證照後,根據證照上的方法,自己生成一個證照編號,如果生成的證照編號與證照上的證照編號一致,說明這個證照是真實的。當然這個數字簽名也是被第三方機構加密的。

最終雙方通訊的金鑰為:客戶端生成的隨機數+服務端生成的隨機數+per-master(這個參考相關文件筆記)

一句話總結HTTPS

其實HTTPS本身就非常複雜了,不是一句話能總結的。但是大牛還是這麼做了。

HTTPS要使客戶端與伺服器端的通訊過程得到安全的保證。必須使用對稱加密,但是協商對稱金鑰的過程,需要使用非對稱加密演算法來保證安全,然而直接使用非對稱加密的過程本身就不安全,會有中間人篡改公鑰的可能性,所以客戶端與伺服器不直接使用公鑰,而是使用數字證照籤發機構頒發的證照來保證非對稱加密過程本身的安全。這樣通過這種機制協商出一個對稱加密演算法,之後雙方再使用該演算法進行加解密,從而解決了客戶端與服務端之間的通訊安全問題。

 

參考資料:

圖解SSL/TLS協議

HTTPS為什麼安全

HTTPS通俗解釋

相關文章