推薦閱讀 小林coding HTTP篇
文章目錄
- HTTP 80
- HTTP 響應碼
- 1xx:信息性狀態碼(Informational)
- 2xx:成功狀態碼(Success)
- 3xx:重定向狀態碼(Redirection)
- 4xx:客戶端錯誤(Client Error)
- 5xx:服務器錯誤(Server Error)
- 常見字段
- GET POST
- HTTP/1 /2 /3
- HTTP/1.0
- HTTP/1.1
- HTTP/2
- HTTP/3 【QUIC】
- HTTPS 443
- 加密方式
- 混合加密
- 摘要算法 -> 數字簽名
- 數字證書
- TLS 1.2 握手
- RSA 算法加密
- 過程:
- 原理:
- 為什么安全:
HTTP 80
超文本傳輸協議 HyperText Transfer Protocol
HTTP 響應碼
1xx:信息性狀態碼(Informational)
表示請求已被接收,繼續處理。
-
100 Continue:客戶端應繼續其請求。
-
101 Switching Protocols:服務器同意切換協議。
2xx:成功狀態碼(Success)
表示請求已成功被接收、理解并處理。
- 200 OK:請求成功。
- 201 Created:資源已成功創建,常用于 POST 請求。
- 204 No Content:請求成功,但無返回內容。
3xx:重定向狀態碼(Redirection)
客戶端需要進一步操作才能完成請求。
- 301 Moved Permanently:永久重定向。
- 302 Found(或 Temporary Redirect):臨時重定向。
- 304 Not Modified:資源未修改,可使用緩存。
4xx:客戶端錯誤(Client Error)
請求包含錯誤,客戶端需修改。
- 400 Bad Request:請求無效,服務器無法理解。
- 401 Unauthorized:未授權,需要認證。
- 403 Forbidden:禁止訪問,即使認證也無權。
- 404 Not Found:資源不存在。
- 405 Method Not Allowed:請求方法不被允許。
5xx:服務器錯誤(Server Error)
服務器在處理請求時出錯。
- 500 Internal Server Error:服務器內部錯誤。
- 502 Bad Gateway:網關或代理收到無效響應。
- 503 Service Unavailable:服務器暫時不可用(如超載或維護)。
- 504 Gateway Timeout:網關超時未收到上游服務器響應。
常見字段
-
Host: www.xxx.com 請求中指定對方域名
-
Content-Length: 1000 回應數據長度
-
Connection: Keep-Alive 長連接
-
Content-Type: text/heml; charset=utf-8 數據格式
(請求方可以指定格式: Accept: /) -
Content-Encoding: gzip 編碼,即壓縮方法
(Accept-Encoding: gzip, deflate)
GET POST
-
GET 的語義是從服務器獲取指定的資源
安全且冪等,因為是只讀,服務器數據是安全的,每次請求結果是相同的。 -
POST 的語義是根據請求負荷(報文body)對指定的資源做出處理
不冪等,會修改資源。
HTTP/1 /2 /3
HTTP/1.0
每個請求都要新建一個TCP連接(三次握手),而且是串行請求 —— 發出A請求,并且收到回復后,四次揮手。接著三次握手開始發送B請求 … 【請求的隊頭阻塞】
HTTP/1.1
使用長連接的通信方式。
進而支持進行管道(pipeline)網絡傳輸 —— 即 A 請求發送后,就可以發出B請求了。不過A請求的響應處理完之后才能處理B請求的響應。 【響應的隊頭阻塞】
其他缺點:
請求頭部沒有壓縮,每次交互都會發送完整頭部,而且是純文本形式。
沒有請求優先級控制。
請求只能從客戶端開始,服務器只能被動響應。
HTTP/2
-
頭部壓縮
如果你同時發出多個請求,他們的頭是一樣的或是相似的,那么協議會幫你消除重復的部分。
HPACK 算法壓縮:在客?端和服務器同時維護?張頭信息表,所有字段都會存?這個表,?成?個索引號,以后就不發送同樣字段了,只發送索引號,這樣就提?速度了。 -
二進制格式
全面采用了二進制格式,頭信息和數據體都是二進制,并且統稱為幀(frame):頭信息幀(Headers Frame)和數據幀(Data Frame)。
如狀態碼200:由 ‘2’‘0’‘0’ 三個字符 -> HPACK 的靜態表編碼是 8,1個字節 10001000 -
并發傳輸
引出了 Stream 概念,多個 Stream 復用在一條 TCP 連接。
針對不同的 HTTP 請求用獨一無二的 Stream ID 來區分,接收端可以通過 Stream ID 有序組裝成 HTTP 消息,不同 Stream 的幀是可以亂序發送的 。
即可以并行交錯地發送請求和響應。
-
服務器主動推送資源
客戶端和服務器雙方都可以建立 Stream,客戶端建立的 Stream 必須是奇數號,而服務器建立的 Stream 必須是偶數號。
比如獲取HTML文件后,還需要依賴的CSS來渲染,這時就不需要再次發送請求了,而是服務器主動推送相關資源。
不過,
因為是基于 TCP 協議傳輸數據,TCP層保證了收到的字節流數據是完整且連續的才會返回給應用層
—— 那么當「前 1 個字節數據」沒有到達時,后收到的字節數據只能存放在內核緩沖區里等待 【HTTP/2 隊頭阻塞問題】
而且一旦發生丟包現象,就會觸發TCP重傳機制,連接中所有的HTTP請求仍然得接著等待
實際上 HTTP/2 的效率并不比 HTTP/1.1 快很多,對于多個數據流,HTTP/1.1 通過建立多個 TCP 連接的方式也能處理。
HTTP/3 【QUIC】
基于 UDP 的 QUIC 協議
-
無隊頭阻塞
QUIC 自己的機制可以保證傳輸的可靠性的。當某個流發生丟包時,只會阻塞這個流,其他流不會受到影響,因此不存在隊頭阻塞問題。
-
更快的連接建立
對于 HTTP/1 和 HTTP/2 協議,TCP 和 TLS 是分層的,分別屬于內核實現的傳輸層、openssl 庫實現的表示層,因此它們難以合并在一起,需要分批次來握手,先 TCP 握手,再 TLS 握手。
而 QUIC 協議握手會在QUIC幀內包含 TLS/1.3,只需要 1 RTT 就可以「同時」完成建立連接與密鑰協商。
甚至,在第二次連接的時候(如會話恢復),應用數據包可以和 QUIC 握手信息一起發送,達到 0-RTT 的效果。
-
連接遷移
QUIC 協議通過連接 ID 來標記通信的兩個端點。
即使設備網絡變化,IP地址等變了,只要仍保有上下文信息(比如連接 ID、TLS 密鑰等),就可以“無縫”地復用原連接,消除重連的成本,沒有絲毫卡頓感,達到了連接遷移的功能。
基于 TCP 傳輸協議的 HTTP 協議,由于是通過四元組(源 IP、源端口、目的 IP、目的端口)確定一條 TCP 連接。
那么當移動設備的網絡從 4G 切換到 WIFI 時,意味著 IP 地址變化了,那么就必須要斷開連接,然后重新建立連接。而建立連接的過程包含 TCP 三次握手和 TLS 四次握手的時延,以及 TCP 慢啟動的減速過程,給用戶的感覺就是網絡突然卡頓了一下,因此連接的遷移成本是很高的。
HTTPS 443
HTTP 是明文傳輸,不安全。
HTTPS 在 HTTP層與TCP層之間添加了TLS協議(傳輸層安全性協議 Transport Layer Security)
TCP三次握手后還要進行 TLS 握手
SSL :安全套接層 Secure Sockets Layer
HTTPS 一定安全可靠
加密方式
以下幾個結合,分別確保 消息加密,消息不被篡改,中間人無法偽造
混合加密
-
在通信建立前采用非對稱加密的方式交換「會話秘鑰」
RSA 算法 (非對稱加密算法) -
在通信過程中全部使用對稱加密的「會話秘鑰」
摘要算法 -> 數字簽名
用摘要算法(哈希函數)來計算出內容的哈希值
對方也對內容計算,比較兩個哈希值。
通過「私鑰加密,公鑰解密」的方式,保證消息不會被冒充
(但是公鑰仍可能是中間人冒充的 —— 中間人攻擊 !)
數字證書
Certificate Authority 證書授權
瀏覽器內置證書!里面有公鑰
客戶端驗證流程:
證書信任鏈的問題:
如百度證書,可能證書是中間證書簽發的
不是根證書,就無法根據本地已有的根證書中的公鑰去驗證 證書是否可信,于是向 CA 請求該中間證書,直到根證書。
電腦系統內置的根證書:
TLS 1.2 握手
基于 RSA 算法的 TLS 握手過程(TLS 1.2 with RSA key exchange):
- ClientHello
客戶端發起加密通信請求 【支持的TLS協議版本;加密用隨機數;支持的加密算法】 - SeverHello
服務器回應客戶端 【確認TLS版本;加密用隨機數;確認使用的加密算法;服務器證書】 - 客戶端回應
客戶端先通過瀏覽器或操作系統內置的 CA 公鑰,確認服務器的數字證書的真實性。
如果證書沒有問題,客戶端會從數字證書中取出服務器的公鑰,然后使用它加密報文。
接著發送【 預主密鑰 ;加密通信算法改變通知;客戶端握手結束通知】,同時自己用前面兩個隨機數+預主密鑰生成了本次通信用的公鑰——會話密鑰。 - 服務器的最后回應
服務器也通過同樣的方式計算出會話密鑰
也向客戶端發送最后的信息:【加密通信算法改變通知;服務器握手結束通知】
之后通過 會話密鑰 加密 HTTP 通信即可。
RSA 握手“不那么安全”
一旦服務器私鑰泄露,歷史通信就可以被解密(前向保密性差)
現在主流推薦使用的是 TLS 1.3 ECDHE(橢圓曲線 Diffie-Hellman Ephemeral),支持前向保密。
RSA 算法加密
需要先了解一些數論:
- 歐拉函數 φ ( n ) φ(n) φ(n) 表示小于等于 n 且與 n互質的正整數的個數。對質數而言就是 n-1
- 歐拉定理:對于任意兩個互質的正整數 a, n , 有 a φ ( n ) ≡ 1 ( m o d n ) a^{φ(n)} ≡1\pmod n aφ(n)≡1(modn)
(≡ 是模意義下同余) - 費馬小定理: 如果 p 是一個質數,a是一個整數且 a 與 p 互質,那么 a p ? 1 ≡ 1 ( m o d p ) a^{p ? 1} ≡ 1 \pmod p ap?1≡1(modp)
過程:
-
選擇兩個大質數 p , q p, q p,q
模數 n = p ? q n = p*q n=p?q 作為我們的模數 -
n 的歐拉函數 φ ( n ) = ( p ? 1 ) ( q ? 1 ) φ (n) = (p-1)(q-1) φ(n)=(p?1)(q?1)
-
加密指數 e e e ,取數 e 與 φ (n) 互質
e 模逆元設為 d d d ,即 e d ≡ 1 ( m o d φ ( n ) ) ed ≡ 1 \pmod {φ(n)} ed≡1(modφ(n)) (逆元其實就是倒數,取模意義下的)
可得 ed 其實就是 k ? φ ( n ) + 1 k*φ(n) + 1 k?φ(n)+1
-
加密明文 m :
密文 c = m e m o d n c = m^e \mod n c=memodn
可以看到就是對原數據求冪 -
解密:
m = c d m o d n m = c^d \mod n m=cdmodn
原理:
整個過程就是先求明文 m 的 e 次冪,然后求 m^e 的 d 次冪
( m e ) d ( m o d n ) ({m^{e}})^{d} \pmod n (me)d(modn)
即
m e d ( m o d n ) {m^{ed}} \pmod n med(modn)
而由上可知 ed = k*φ(n) + 1 ,以及 歐拉定理中 m^φ(n) 取模n后為 1
所以上述表達式最終取模后為 m 本身 ?
為什么安全:
模數 n 是公開的, e 是加密指數可作為公鑰。
但是推出解密指數,需要得出 φ (n) ,這需要選擇出正確的質數 p, q 。
“大整數分解難題” 將一個大整數 n 分解成兩個質數 p 和 q 是非常困難的
當 n 是一個 2048 位的大整數時,它的兩個因數 p 和 q 也是大質數(每個約 1024 位),在現有技術和算法下,分解這樣的大整數需要數十億年