計算機網絡之HTTP、HTTPS、HTTP2

一、HTTP

HTTP 協議,是 Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫,是用於從萬維網(WWW:World Wide Web )服務器傳輸超文本到本地瀏覽器的傳送協議。

HTTP 是一個無狀態的協議。無狀態是指客戶機(Web 瀏覽器)和服務器之間不需要建立持久的連接,這意味着當一個客戶端向服務器端發出請求,然後服務器返回響應(response),連接就被關閉了,在服務器端不保留連接的有關信息。HTTP 遵循請求(Request)/應答(Response)模型。客戶機(瀏覽器)向服務器發送請求,服務器處理請求並返回適當的應答。所有 HTTP 連接都被構造成一套請求和應答。

主要特點如下:

  • 簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法常用的有 GET、HEAD、POST 等等。每種方法規定了客戶與服務器聯繫的類型不同。由於 HTTP 協議簡單,使得 HTTP 服務器的程序規模小,因而通信速度很快。

  • 數據格式靈活:HTTP 允許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type 加以標記。

  • 無連接:無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答後,即斷開連接。採用這種方式可以節省傳輸時間。

    主要指的是不使用 Keep-Alive 機制的情況下。

  • 無狀態:HTTP 協議是無狀態協議。無狀態,是指協議對於事務處理沒有記憶能力。無狀態意味着如果後續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送的數據量增大。另一方面,在服務器不需要先前信息時它的應答就較快。

    無狀態,所以更容易做服務的擴容,支撐更大的訪問量。

  • 支持 B/S 及 C/S 模式。

    另外,HTTP 協議已經不僅僅使用在瀏覽器上。在前後端分離的架構中,又或者微服務架構的內部通信中,HTTP 因爲其數據格式的通用性,和語言無關,被大規模使用。

HTTP 基本格式

參照 《貓哥網絡編程系列:詳解 BAT 面試題》 

🦅 HTTP 請求格式

  • 請求行:用來說明請求類型,要訪問的資源以及所使用的 HTTP 版本。

  • 請求頭部:緊接着請求行(即第一行)之後的部分,用來說明服務器要使用的附加信息從第二行起爲請求頭部。

    • HOST ,將指出請求的目的地。

    • User-Agent ,服務器端和客戶端腳本都能訪問它,它是瀏覽器類型檢測邏輯的重要基礎。該信息由你的瀏覽器來定義,並且在每個請求中自動發送等等

  • 空行:請求頭部後面的空行是必須的。

  • 請求數據:也叫主體,可以添加任意的其他數據。

HTTP 響應格式

  • 狀態行:由 HTTP 協議版本號、狀態碼、狀態消息三部分組成。

  • 消息報頭:用來說明客戶端要使用的一些附加信息。

  • 空行:消息報頭後面的空行是必須的。

  • 響應正文:服務器返回給客戶端的文本信息。

URI 和 URL 的區別

1. URI

Web上可用的每種資源如HTML文檔、圖像、視頻片段、程序等都是一個來URI來定位的; URI一般由三部組成:

①訪問資源的命名機制 ②存放資源的主機名 ③資源自身的名稱,由路徑表示,着重強調於資源。

2. URL

URL是Internet上用來描述信息資源的字符串,主要用在各種WWW客戶程序和服務器程序上,特別是著名的Mosaic。 採用URL可以用一種統一的格式來描述各種信息資源,包括文件、服務器的地址和目錄等。 URL一般由三部組成

①協議(或稱爲服務方式) ②存有該資源的主機IP地址(有時也包括端口號) ③主機資源的具體地址。如目錄和文件名等

《URI 和 URL 的區別》 文章。

HTTP 協議請求方法

  • GET: 對服務器資源的簡單請求。

  • POST: 用於發送包含用戶提交數據的請求。

  • HEAD:類似於 GET 請求,不過返回的響應中沒有具體內容,用於獲取報頭。

  • PUT:傳說中請求文檔的一個版本。

  • DELETE:發出一個刪除指定文檔的請求。

  • TRACE:發送一個請求副本,以跟蹤其處理進程。

  • OPTIONS:返回所有可用的方法,檢查服務器支持哪些方法。

  • CONNECT:用於 SSL 隧道的基於代理的請求。

GET 和 POST 的區別

請求方式 數據位置 明文密文 數據安全 長度限制 應用場景
GET HTTP 請求的 path 中 明文 不安全 長度較小,一般 2k 查詢數據
POST HTTP 請求 body 中 可明可密 安全 支持較大數據傳輸 修改數據
  • GET在瀏覽器回退時是無害的,而POST會再次提交請求。

  • GET產生的URL地址可以被添加到書籤,而POST不可以。

  • GET請求會被瀏覽器主動cache,而POST不會,除非手動設置。

  • GET請求只能進行url編碼,而POST支持多種編碼方式。

  • GET請求參數會被完整保留在瀏覽器歷史記錄裏,而POST中的參數不會被保留。

  • GET請求在URL中傳送的參數是有長度限制的,而POST沒有。

  • 對參數的數據類型,GET只接受ASCII字符,而POST沒有限制。

  • GET比POST更不安全,因爲參數直接暴露在URL上,所以不能用來傳遞敏感信息。

  • GET參數通過URL傳遞,POST放在Request body中。

  • GET 請求可被緩存;POST 請求不會被緩存。

  • GET 請求可被收藏爲書籤;POST 不能被收藏爲書籤。

  • 參見 《99%的人理解錯 HTTP 中 GET 與 POST 的區別》

    • 對於 GET 方式的請求,瀏覽器會把 HTTP header 和 data 一併發送出去,服務器響應 200(返回數據)。

    • 而對於 POST,瀏覽器先發送 header ,服務器響應 100 continue ,瀏覽器再發送 data ,服務器響應 200 ok(返回數據)。

    • 本質上來說:get和post本質上都是基於TCP/IP的HTTP協議的請求方式,也就是說這兩者本質上TCP連接。此外,要注意:GET產生一個TCP數據包;POST產生兩個TCP數據包。

    也就是說,GET 只需要汽車跑一趟就把貨送到了,而 POST得跑兩趟,第一趟,先去和服務器打個招呼“嗨,我等下要送一批貨來,你們打開門迎接我”,然後再回頭把貨送過去。

    ps:不過要注意,POST 具體發幾次,也和瀏覽器的實現有關係。例如:Firefox 只發一次。 ps2:據研究,在網絡環境好的情況下,發一次包的時間和發兩次包的時間差別基本可以無視。而在網絡環境差的情況下,兩次包的 TCP 在驗證數據包完整性上,有非常大的優點。

HTTP相關狀態碼

  • 1×× : 請求處理中,請求已被接受,正在處理

  • 2×× : 請求成功,請求被成功處理

    • 200 OK // 客戶端請求成功

  • 3×× : 重定向,要完成請求必須進行進一步處理

    • 301 Moved Permanently // 永久重定向,使用域名跳轉

    • 302 Found // 臨時重定向,未登陸的用戶訪問用戶中心重定向到登錄頁面

  • 4×× : 客戶端錯誤,請求不合法

    • 400 Bad Request // 客戶端請求有語法錯誤,不能被服務器所理解

    • 401 Unauthorized // 請求未經授權,這個狀態代碼必須和 WWW-Authenticate 報頭域一起使用

    • 403 Forbidden // 服務器收到請求,但是拒絕提供服務

    • 404 Not Found // 請求資源不存在,eg:輸入了錯誤的 URL

  • 5×× : 服務器端錯誤,服務器不能處理合法請求

    • 500 Internal Server Error // 服務器發生不可預期的錯誤

    • 502 Bad Gateway //作爲網關或者代理工作的服務器嘗試執行請求時,從上游服務器接收到無效的響應。

    • 503 Server Unavailable // 服務器當前不能處理客戶端的請求,一段時間後可能恢復正常

    • 504 Gateway Time-out //網關超時,這個有時候Nginx會拋出的異常,主要原因是請求超時,比如你想導出下載某個文件,結果文件太大,就可能請求超時了。

完整的狀態碼列表,可以看看 《HTTP 狀態碼》 文章。

forward 和 redirect 的區別

forward(轉發)

是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然後把這些內容再發給瀏覽器。瀏覽器根本不知道服務器發送的內容從哪裏來的,因爲這個跳轉過程實在服務器實現的,並不是在客戶端實現的所以客戶端並不知道這個跳轉動作,所以它的地址欄還是原來的地址.

redirect(重定向)

是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址.所以地址欄顯示的是新的URL.

轉發是服務器行爲,重定向是客戶端行爲。

區別

  1. 從地址欄顯示來說 forward是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然後把這些內容再發給瀏覽器,瀏覽器根本不知道服務器發送的內容從哪裏來的,所以它的地址欄還是原來的地址.

    redirect是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址.所以地址欄顯示的是新的URL.

  2. 從數據共享來說 forward:轉發頁面和轉發到的頁面可以共享request裏面的數據. redirect:不能共享數據.

  3. 從運用地方來說 forward:一般用於用戶登陸的時候,根據角色轉發到相應的模塊. redirect:一般用於用戶註銷登陸時返回主頁面和跳轉到其它的網站等

  4. 從效率來說 forward:高. redirect:低.

本質區別

轉發過程:

客戶瀏覽器發送http請求----》web服務器接受此請求--》調用內部的一個方法在容器內部完成請求處理和轉發動作----》將目標資源發送給客戶;在這裏,轉發的路徑必須是同一個web容器下的url,其不能轉向到其他的web路徑上去,中間傳遞的是自己的容器內的request。在客戶瀏覽器路徑欄顯示的仍然是其第一次訪問的路徑,也就是說客戶是感覺不到服務器做了轉發的。轉發行爲是瀏覽器只做了一次訪問請求。

重定向過程:

客戶瀏覽器發送http請求----》web服務器接受後發送302狀態碼響應及對應新的location給客戶瀏覽器--》客戶瀏覽器發現是302響應,則自動再發送一個新的http請求,請求url是新的location地址----》服務器根據此請求尋找資源併發送給客戶。在這裏 location可以重定向到任意URL,既然是瀏覽器重新發出了請求,則就沒有什麼request傳遞的概念了。在客戶瀏覽器路徑欄顯示的是其重定向的路徑,客戶可以觀察到地址的變化的。重定向行爲是瀏覽器做了至少兩次的訪問請求的。

重定向,其實是兩次request: 第一次,客戶端request A,服務器響應,並response回來,告訴瀏覽器,你應該去B。這個時候IE可以看到地址變了,而且歷史的回退按鈕也亮了。重定向可以訪問自己web應用以外的資源。在重定向的過程中,傳輸的信息會被丟失。

詳細的,請看 《請求轉發(Forward)和重定向(Redirect)的區別》

狀態碼301 與 302 的區別

301,302 都是 HTTP 狀態的編碼,都代表着某個 URL 發生了轉移,不同之處在於:

  • 301 redirect: 301 代表永久性轉移(Permanently Moved)。

  • 302 redirect: 302 代表暫時性轉移(Temporarily Moved)。

詳細的,請看 《HTTP 返回碼中 301 與 302 的區別》 文章。

HTTP、TCP、Socket 的關係

  • TCP/IP 代表傳輸控制協議/網際協議,指的是一系列協議族。

  • HTTP 本身就是一個協議,是從 Web 服務器傳輸超文本到本地瀏覽器的傳送協議。

  • Socket 是 TCP/IP 網絡的 API ,其實就是一個門面模式,它把複雜的 TCP/IP 協議族隱藏在 Socket 接口後面。對用戶來說,一組簡單的接口就是全部,讓 Socket 去組織數據,以符合指定的協議。

綜上所述:

  • 需要 IP 協議來連接網絡

  • TCP 是一種允許我們安全傳輸數據的機制,使用 TCP 協議來傳輸數據的 HTTP 是 Web 服務器和客戶端使用的特殊協議。

  • HTTP 基於 TCP 協議,所以可以使用 Socket 去建立一個 TCP 連接。

Cookies 和 Session 的區別

  • Session 在服務器端,Cookie 在客戶端(瀏覽器)。

    Session 默認被存在在服務器的一個文件裏(不是內存)。

  • Session 的運行依賴 sessionid ,而 sessionid 是存在 Cookie 中的,也就是說,如果瀏覽器禁用了 Cookie ,同時 session 也會失效。但是,可以通過其它方式實現,比如在 url 參數中傳遞 sessionid 。

  • Session 可以放在文件、數據庫、或內存中都可以。

  • 【關鍵】用戶驗證這種場合一般會用 Session

參照:https://blog.csdn.net/striveb/article/details/82469253#Session%E4%B8%8ECookie%E5%8C%BA%E5%88%AB

一次完整的 HTTP 請求所經歷的步驟

這裏的客戶端,更多指的是瀏覽器。

  • 1、DNS 解析(通過訪問的域名找出其 IP 地址,遞歸搜索)。

    如用客戶端瀏覽器請求這個頁面:http://localhost.com:8080/index.htm 從中分解出協議名、主機名、 端口、對象路徑等部分,對於我們的這個地址,解析得到的結果如下:

    協議名:http

    主機名:localhost.com

    端口:8080

    對象路徑:/index.htm

    在這一步,需要域名系統 DNS 解析域名 localhost.com,得主機的 IP 地址。

  • 2、HTTP 請求,當輸入一個請求時,建立一個 Socket 連接發起 TCP的 3 次握手。

    把以上部分結合本機自己的信息,封裝成一個 HTTP 請求數據包。

    如果是 HTTPS 請求,會略微有不同。

  • 3、客戶端發送請求

    • 3.1 客戶端向服務器發送請求命令(一般是 GET 或 POST 請求)。

    客戶端的網絡層不用關心應用層或者傳輸層的東西,主要做的是通過查找路由表確定如何到達服務器,期間可能經過多個路由器,這些都是由路由器來完成的工作,無非就是通過查找路由表決定通過那個路徑到達服務器。

    客戶端的鏈路層,包通過鏈路層發送到路由器,通過鄰居協議查找給定 IP 地址的 MAC 地址,然後發送 ARP 請求查找目的地址,如果得到迴應後就可以使用 ARP 的請求應答交換的 IP 數據包現在就可以傳輸了,然後發送 IP 數據包到達服務器的地址。

    客戶機發送請求命令:建立連接後,客戶機發送一個請求給服務器,請求方式的格式爲:統一資源標識符(URL)、協議版本號,後邊是 MIME 信息包括請求修飾符、客戶機信息和可內容。

    • 3.2客戶端發送請求頭信息和數據。

  • 4.1、服務器發送應答頭信息。

    服務器接到請求後,給予相應的響應信息,其格式爲一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,後邊是 MIME 信息包括服務器信息、實體信息和可能的內容。

  • 4.2、服務器向客戶端發送數據。

  • 5、服務器關閉 TCP 連接(4次揮手)。

    這裏是否關閉 TCP 連接,也根據 HTTP Keep-Alive 機制有關。同時,客戶端也可以主動發起關閉 TCP 連接。

    如果瀏覽器或者服務器在其頭信息加入了這行代碼 Connection:keep-alive,TCP 連接在發送後將仍然保持打開狀態,於是,瀏覽器可以繼續通過相同的連接發送請求。保持連接節省了爲每個請求建立新連接所需的時間,還節約了網絡帶寬。

  • 6、客戶端根據返回的 HTML、CSS、JS 進行渲染。

如下是《圖解HTTP》提供的圖片:

HTTP1.0 和 HTTP1.1的區別

主要是如下 8 點:

  • 1、可擴展性

  • 2、緩存

  • 3、帶寬優化

    帶來了分塊傳輸

    HTTP/1.1中在請求消息中引入了range頭域,它允許只請求資源的某個部分。在響應消息中Content-Range頭域聲明瞭返回的這部分對象的偏移值和長度。如果服務器相應地返回了對象所請求範圍的內容,則響應碼爲206(Partial Content),它可以防止Cache將響應誤以爲是完整的一個對象。

    HTTP/1.1加入了一個新的狀態碼100(Continue)。客戶端事先發送一個只帶頭域的請求,如果服務器因爲權限拒絕了請求,就回送響應碼401(Unauthorized);如果服務器接收此請求就回送響應碼100,客戶端就可以繼續發送帶實體的完整請求了。注意,HTTP/1.0的客戶端不支持100響應碼。但可以讓客戶端在請求消息中加入Expect頭域,並將它的值設置爲100-continue。

  • 4、長連接

    HTTP 1.1支持長連接(PersistentConnection)和請求的流水線(Pipelining)處理,在一個TCP連接上可以傳送多個HTTP請求和響應,減少了建立和關閉連接的消耗和延遲。例如:一個包含有許多圖像的網頁文件的多個請求和應答可以在一個連接中傳輸,但每個單獨的網頁文件的請求和應答仍然需要使用各自的連接。

    HTTP 1.1還允許客戶端不用等待上一次請求結果返回,就可以發出下一次請求,但服務器端必須按照接收到客戶端請求的先後順序依次回送響應結果,以保證客戶端能夠區分出每次請求的響應內容,這樣也顯著地減少了整個下載過程所需要的時間。

    在HTTP/1.0中,要建立長連接,可以在請求消息中包含Connection: Keep-Alive頭域,如果服務器願意維持這條連接,在響應消息中也會包含一個Connection: Keep-Alive的頭域。同時,可以加入一些指令描述該長連接的屬性,如max,timeout等。

  • 5、消息傳遞

  • 6、Host 頭域

  • 7、錯誤提示

  • 8、內容協商

詳細的每一點的說明,可以看 《HTTP1.0 與 HTTP1.1 的區別》 文章,特別是第 4 點【長連接】。

HTTP1.1 支持長連接(PersistentConnection)和請求的流水線(Pipelining)。

  • 長連接(PersistentConnection):處理在一個 TCP 連接上可以傳送多個 HTTP 請求和響應,減少了建立和關閉連接的消耗和延遲。在 HTTP1.1中 默認開啓Connection:keep-alive ,一定程度上彌補了 HTTP1.0 每次請求都要創建連接的缺點。

  • 請求的流水線(Pipelining):HTTP1.1 還允許客戶端不用等待上一次請求結果返回,就可以發出下一次請求,但服務器端必須按照接收到客戶端請求的先後順序依次回送響應結果,以保證客戶端能夠區分出每次請求的響應內容,這樣也顯著地減少了整個下載過程所需要的時間。

推薦,在看看 《HTTP Keep-Alive 是什麼?如何工作?》 文章。

關於這一點,可能演變的問題有:

  • HTTP 的長連接是什麼意思?

  • HTTP Keep-Alive 機制是什麼?

  • HTTP Keep-Alive 機制和 TCP Keep-Alive 有什麼區別?

SPDY 是什麼?

HTTP Working-Group 最終決定以 SPDY/2 爲基礎,開發 HTTP/2 。

2012 年,Google 如一聲驚雷提出了 SPDY 的方案,優化了 HTTP1.X 的請求延遲,解決了 HTTP1.X 的安全性,具體如下:

  • 1、降低延遲

    針對 HTTP 高延遲的問題,SPDY 優雅的採取了多路複用(multiplexing)。多路複用通過多個請求 Stream 共享一個 Tcp連 接的方式,解決了 HOL blocking 的問題,降低了延遲同時提高了帶寬的利用率。

  • 2、請求優先級(request prioritization)

    多路複用帶來一個新的問題是,在連接共享的基礎之上有可能會導致關鍵請求被阻塞。SPDY 允許給每個 request 設置優先級,這樣重要的請求就會優先得到響應。

    比如瀏覽器加載首頁,首頁的 html 內容應該優先展示,之後纔是各種靜態資源文件,腳本文件等加載,這樣可以保證用戶能第一時間看到網頁內容。

  • 3、header 壓縮

    前面提到 HTTP1.x 的 header 很多時候都是重複多餘的。選擇合適的壓縮算法可以減小包的大小和數量。

  • 4、基於 HTTPS 的加密協議傳輸

    大大提高了傳輸數據的安全性。

  • 5、服務端推送(server push)

    採用了 SPDY 的網頁,例如我的網頁有一個 sytle.css 的請求,在客戶端收到 sytle.css 數據的同時,服務端會將 sytle.js 的文件推送給客戶端。當客戶端再次嘗試獲取 sytle.js 時就可以直接從緩存中獲取到,不用再發請求了。

    和我們理解的服務端推送,有點(非常)不一樣哈。

SPDY 構成圖如下:

  • SPDY 位於 HTTP 之下,TCP 和 SSL 之上,這樣可以輕鬆兼容老版本的 HTTP 協議(將 HTTP1.x 的內容封裝成一種新的 frame 格式),同時可以使用已有的 SSL 功能。

二、HTTPS

簡述

HTTPS ,實際就是在 TCP 層與 HTTP 層之間加入了 SSL/TLS 來爲上層的安全保駕護航,主要用到對稱加密、非對稱加密、證書,等技術進行客戶端與服務器的數據加密傳輸,最終達到保證整個通信的安全性。

一句話概括:HTTP + 加密 + 認證 + 完整性保護 = HTTPS

SSL和TLS

官方定義,SSL 是安全套接層(secure sockets layer);TLS 是 SSL 的繼任者,叫傳輸層安全(transport layer security)。

它們存在的唯一目的就是保證上層通訊安全的一套機制。它的發展依次經歷了下面幾個時期,像手機軟件升級一樣,每次更新都添加或去除功能,比如引進新的加密算法,修改握手方式等。

  • SSL1.0: 已廢除

  • SSL2.0: RFC6176 ,已廢除

  • SSL3.0: RFC6101 ,基本廢除

  • TLS1.0: RFC2246 ,目前大都採用此種方式

  • TLS1.1: RFC4346

  • TLS1.2: RFC5246 ,沒有廣泛使用

  • TLS1.3: IETF 正在醞釀中

爲了下面描述方便,統一先叫 SSL 。

SSL/TLS 協議作用

  1. 認證用戶和服務器,確保數據發送到正確的客戶機和服務器。

    客戶端必須避免中間人攻擊,即除了真正的服務器,任何第三方都無法冒充服務器。

  2. 加密數據以防止數據中途被竊取。

  3. 維護數據的完整性,確保數據在傳輸過程中不被改變。

HTTPS實現的過程

1.建立連接獲取證書

SSL 客戶端通過 TCP 和服務器建立連接之後(443 端口),並且在一般的 tcp 連接協商(握 手)過程中請求證書。即客戶端發出一個消息給服務器,這個消息裏面包含了自己可實現的算法列表和其它一些需要的消息,SSL 的服務器端會迴應一個數據包,這裏面確定了這次通信所需要的算法,然後服務器向客戶端返回證書。(證書裏面包含了服務器信息:域名,申請證書 的公司,公共祕鑰)。

2.證書驗證

Client 在收到服務器返回的證書後,判斷簽發這個證書的公共簽發機構,並使用這個機構的公 共祕鑰確認簽名是否有效,客戶端還會確保證書中列出的域名就是它正在連接的域名。

3.數據加密和傳輸

如果確認證書有效,那麼生成對稱祕鑰並使用服務器的公共祕鑰進行加密。然後發送給服務器,服務器使用它的私鑰對它進行解密,這樣兩臺計算機可以開始進行對稱加密進行通信。

HTTP 和 HTTPS 的區別

  • 端口不同:HTTP 與 HTTPS 使用不同的連接方式,用的端口也不一樣,前者是 80,後者是 443。

  • 資源消耗:和 HTTP 通信相比,HTTPS 通信會由於加解密處理消耗更多的 CPU 和內存資源。

  • 開銷:HTTPS 通信需要證書,而證書一般需要向認證機構申請免費或者付費購買。

    HTTPS 可以有效的防止運營商劫持,解決了防劫持的一個大問題。

SSL 加密方式

  • 對稱密鑰加密,是指加密和解密使用同一個密鑰的方式,這種方式存在的最大問題就是密鑰發送問題,即如何安全地將密鑰發給對方。

  • 非對稱加密,指使用一對非對稱密鑰,即公鑰和私鑰,公鑰可以隨意發佈,但私鑰只有自己知道。發送密文的一方使用對方的公鑰進行加密處理,對方接收到加密信息後,使用自己的私鑰進行解密。

SSL 協議,即用到了對稱加密也用到了非對稱加密,如下圖所示:

  • 在建立傳輸鏈路時,SSL 首先對對稱加密的密鑰使用公鑰進行非對稱加密。

    注意,這裏 Server 返回給 Client 的不是公鑰( server.pub ),而是 server.crt 。Client 需要使用 ca.keyserver.crt 中解密出公鑰( server.pub ) 。

  • 鏈路建立好之後,SSL 對傳輸內容使用公鑰( server.pub )對稱加密。

公鑰傳輸的步驟

1.對公鑰加密

每一個使用 HTTPS 的服務器都必須去專門的證書機構註冊一個證書,證書中存儲了用權威機構私鑰加密的公鑰。這樣客戶端用權威機構的公鑰解密就可以了。

現在 HTTPS 協議的握手階段變成了四步:

  1. 客戶端: 你好,我要發起一個 HTTPS 請求,請給我公鑰

  2. 服務器: 好的,這是我的證書,裏面有加密後的公鑰

  3. 客戶端: 解密成功以後告訴服務器: 這是我的 (用公鑰加密後的) 對稱祕鑰。

  4. 服務器: 好的,我知道你的祕鑰了,後續就用它傳輸。

2.權威機構的公鑰的傳輸

可以存在電腦裏,這個公鑰不用傳輸,會直接內置在各大操作系統(或者瀏覽器)的出廠設置裏。之所以不把每個服務器的公鑰內置在電腦裏,一方面是因爲服務器太多,存不過來。另一方面操作系統也不信任你,憑什麼你說你這個就是百度/淘寶的證書呢?

所以各個公司要先去權威機構認證,申請證書,然後操作系統只會存儲權威機構的公鑰。因爲權威機構數量有限,所以操作系統廠商相對來說容易管理。如果這個權威機構不夠權威,亂髮證書,就會取消他的資格,比如可憐的沃通。

3. 將信息 hash 值隨着信息一起傳遞

哈希算法的特點是它可以壓縮數據,如果從函數角度來看,不管多複雜的數據(定義域可以非常大)經過哈希算法都會得到一個值,而且這個值處在某個特定(遠小於定義域的範圍)值域內。相同數據的哈希結果一定相同,不相同數據的哈希結果一般不同,不過也有小概率會重複,這叫哈希衝突。

爲了確保原始證書沒有被篡改,我們可以在傳遞證書的同時傳遞證書的哈希值。由於第三者無法解析數據,只能亂改,那麼修改後的數據在解密後,就不可能通過哈希。

比如說公鑰就是之前的例子 Hello,我們假設哈希算法是獲取字符串的最後一個字符,那麼 Hello 的哈希值就是 o,所以加密字符串是 Ifmmpp。雖然公鑰已知,每個人都可以解密,解密完也可以篡改,但是因爲沒有私鑰, 所以無法正確的加密。所以它再返回給客戶端的數據是無效數據,用公鑰解析後會得到亂碼。即使攻擊者通過多次嘗試碰巧能夠解析,也無法通過哈希校驗。

4.可以防止第三方冒充服務器

首先真正的服務器下發的內容,無法被別人篡改。他們有權威機構的公鑰,所以可以解密,但是因爲沒有私鑰,所以解密以後的信息無法加密。沒有加密或者錯誤加密的信息被客戶端用公鑰解密以後,必然無法通過哈希校驗。

但是,如果你一開始請求的就不是真的服務器,而是一個攻擊者,此時的他完全有機會進行中間人攻擊。我們知道第一次握手的時候服務器會下發用於證明自己身份的證書,這個證書會用預設在設備上的公鑰來解密。所以要麼是經過認證的證書用權威機構的私鑰加密,再用權威機構解密,要麼是用非權威機構的私鑰加密,然後找不到公鑰解密。

所以如果不小心安裝過非權威機構的根證書,比如黑客提供的惡意證書,這時候設備上就多了一個預設的公鑰,那麼用惡意私鑰加密的證書就能被正常解析出來。所以千萬不要隨便裝根證書,這等於是爲那些惡意證書留了一扇門。

當然,凡是都有兩面性。我們知道 Charles 可以調試 HTTPS 通信,它的原理就是需要用戶安裝 Charles 的根證書,然後我們的請求會被代理到 Charles 服務器,它下發的 Charles 證書才能被正確解析。另一方面,Charles 會作爲客戶端,從真正的服務器哪裏拿到正確的 https 證書並用於後續通信。幸好 Charles 不是流氓軟件,或者它的私鑰一旦泄露,對用戶都會造成很大的影響。

參照 《九個問題從入門到熟悉 HTTPS》

也就是說,通過 CA 來保證。至於 server.crt 證書是怎麼申請的呢?請看 《SSL/TLS 雙向認證(一) – SSL/TLS工作原理》 文章的 「CA 的證書 ca.crt 和 SSL Server 的證書 server.crt 是什麼關係呢? 」 問題的解答。

單向認證、雙向認證

  • 單向認證,指的是隻有一個對象校驗對端的證書合法性。

    通常都是 Client 來校驗服務器的合法性。那麼 Client 需要一個ca.crt ,服務器需要 server.crtserver.key

  • 雙向認證,指的是相互校驗,Server 需要校驗每個 Client ,Client 也需要校驗服務器。

    • Server 需要 server.keyserver.crtca.crt

    • Client 需要 client.keyclient.crtca.crt

1)單向認證的過程

單向認證

  • 1、客戶端向服務端發送 SSL 協議版本號、加密算法種類、隨機數等信息。

  • 2、服務端給客戶端返回 SSL 協議版本號、加密算法種類、隨機數等信息,同時也返回服務器端的證書,即公鑰證書。

  • 3、客戶端使用服務端返回的信息驗證服務器的合法性,包括:

    • 證書是否過期。

    • 發行服務器證書的 CA 是否可靠。

    • 返回的公鑰是否能正確解開返回證書中的數字簽名。

    • 服務器證書上的域名是否和服務器的實際域名相匹配

      驗證通過後,將繼續進行通信;否則,終止通信。

    4、客戶端向服務端發送自己所能支持的對稱加密方案,供服務器端進行選擇。

    5、服務器端在客戶端提供的加密方案中選擇加密程度最高的加密方式。

  • 6、服務器將選擇好的加密方案通過明文方式返回給客戶端。

  • 7、客戶端接收到服務端返回的加密方式後,使用該加密方式生成產生隨機碼,用作通信過程中對稱加密的密鑰,使用服務端返回的公鑰進行加密,將加密後的隨機碼發送至服務器。

  • 8、服務器收到客戶端返回的加密信息後,使用自己的私鑰進行解密,獲取對稱加密密鑰。

    在接下來的會話中,服務器和客戶端將會使用該密碼進行對稱加密,保證通信過程中信息的安全

2)雙向認證的過程

雙向認證和單向認證原理基本差不多,只是除了客戶端需要認證服務端以外,增加了服務端對客戶端的認證,具體過程如下:

雙向認證

  • 1、客戶端向服務端發送 SSL 協議版本號、加密算法種類、隨機數等信息。

  • 2、服務端給客戶端返回 SSL 協議版本號、加密算法種類、隨機數等信息,同時也返回服務器端的證書,即公鑰證書。

  • 3、客戶端使用服務端返回的信息驗證服務器的合法性,包括:

    • 證書是否過期。

    • 髮型服務器證書的 CA 是否可靠。

    • 返回的公鑰是否能正確解開返回證書中的數字簽名。

    • 服務器證書上的域名是否和服務器的實際域名相匹配

      驗證通過後,將繼續進行通信;否則,終止通信。

    • 【新增】4、服務端要求客戶端發送客戶端的證書,客戶端會將自己的證書發送至服務端。

    • 【新增】5、驗證客戶端的證書,通過驗證後,會獲得客戶端的公鑰。

    • 6、客戶端向服務端發送自己所能支持的對稱加密方案,供服務器端進行選擇。

    • 7、服務器端在客戶端提供的加密方案中選擇加密程度最高的加密方式。

  • 8、服務器將選擇好的加密方案通過明文方式返回給客戶端。

  • 9、客戶端接收到服務端返回的加密方式後,使用該加密方式生成產生隨機碼,用作通信過程中對稱加密的密鑰,使用服務端返回的公鑰進行加密,將加密後的隨機碼發送至服務器。

  • 10、服務器收到客戶端返回的加密信息後,使用自己的私鑰進行解密,獲取對稱加密密鑰。

    在接下來的會話中,服務器和客戶端將會使用該密碼進行對稱加密,保證通信過程中信息的安全

如何選擇單向認證還是雙向認證

  • 一般一個站點很多用戶訪問就用單向認證。

  • 企業接口對接就用雙向認證。

    如果想要提高 APP 的安全級別,也可以考慮雙向認證。因爲,APP 天然方便放入客戶端證書,從而提高安全級別。

爲什麼抓包工具還能抓到 HTTPS 數據包並解密成功呢

不是說HTTPS在網絡中傳輸的是密文嗎?這個問題就是中間者攻擊(man in zhe middle)。

  • 解決辦法,就是 HTTPS 單向驗證。在客戶端中內置服務器公鑰,在第三步服務器返回的公鑰,除了驗證公鑰的有效性之外,再比對公鑰是不是和內置的公鑰一樣,不一樣說明被中間者攻擊了,就斷開鏈接不在請求了。

  • 這個原理的前提是服務器的私鑰沒有泄露,客戶端的代碼不會被破解,道高一尺魔高一丈。信息安全就是在合理的範圍內,選擇比較合適的加密方法,沒有絕對論,只有相對論。在某個範圍內比較安全。

HTTPS 握手對性能的影響

TCP 有三次握手,再加上 HTTPS 的四次握手,影響肯定有,但是可以接受。

  • 首先,HTTPS 肯定會更慢一點,時間主要花費在兩組 SSL 之間的耗時和證書的讀取驗證上,對稱算法的加解密時間幾乎可以忽略不計。

  • 而且如果不是首次握手,後續的請求並不需要完整的握手過程。客戶端可以把上次的加密情況直接發送給服務器從而快速恢復,具體細節可以參考 《圖解 SSL/TLS 協議》

  • 除此以外,SSL 握手的時間並不是只能用來傳遞加密信息,還可以承擔起客戶端和服務器溝通 HTTP2 兼容情況的任務。因此從 HTTPS 切換到 HTTP2.0 不會有任何性能上的開銷,反倒是得益於 HTTP2.0 的多路複用等技術,後續可以節約大量時間。

  • 如果把 HTTPS2.0 當做目標,那麼 HTTPS 的性能損耗就更小了,遠遠比不上它帶來的安全性提升。

八、HTTP2

HTTP2.0簡述

HTTP2.0 ,可以說是SPDY的升級版(其實原本也是基於SPDY設計的),但是,HTTP2.0 跟 SPDY 仍有不同的地方,如下:

  • HTTP2.0 支持明文 HTTP 傳輸,而 SPDY 強制使用 HTTPS 。

  • HTTP2.0 消息頭的壓縮算法採用 HPACK,而非 SPDY 採用的 DEFLATE

HTTP2.0 和 HTTP1.X 相比的新特性

  • 1、新的二進制格式(Binary Format)

    HTTP1.x 的解析是基於文本。基於文本協議的格式解析存在天然缺陷,文本的表現形式有多樣性,要做到健壯性考慮的場景必然很多,二進制則不同,只認 0 和 1 的組合。基於這種考慮 HTTP2.0 的協議解析決定採用二進制格式,實現方便且健壯。

  • 同 SPDY 對 HTTP1.1 的改進。

    • 2、降低延遲

    • 3、多路複用(MultiPlexing)

    • 4、header 壓縮

    • 5、服務端推送(server push)

總的區別可以理解爲:

  1. HTTP/2採用二進制格式而非文本格式

  2. HTTP/2是完全多路複用的,而非有序並阻塞的——只需一個連接即可實現並行

  3. 使用報頭壓縮,HTTP/2降低了開銷

  4. HTTP/2讓服務器可以將響應主動“推送”到客戶端緩存中

Nginx 怎麼做 HTTP2.0 的升級改造?

  • 1、雖然 HTTP2.0 其實可以支持非 HTTPS 的,但是現在主流的瀏覽器像 Chrome,Firefox 表示還是隻支持基於 TLS 部署的 HTTP2.0協議,所以要想升級成 HTTP2.0 還是先升級 HTTPS 爲好。

  • 2、當你的網站已經升級 HTTPS 之後,那麼升級 HTTP2.0 就簡單很多,如果你使用 NGINX ,只要在配置文件中啓動相應的協議就可以了,可以參考 NGINX白皮書NGINX配置HTTP2.0官方指南

  • 3、使用了 HTTP2.0 那麼,原本的 HTTP1.x 怎麼辦?這個問題其實不用擔心,HTTP2.0 完全兼容 HTTP1.x 的語義,對於不支持 HTTP2.0 的瀏覽器,NGINX 會自動向下兼容的。

在我們內部的微服務 API 接口,也可以做 HTTP2 的改造,可以參考如下文章:

HTTP2.0 的多路複用和 HTTP1.X 中的長連接複用區別

  • HTTP/1.0:一次請求-響應,建立一個連接,用完關閉;每一個請求都要建立一個連接。

  • HTTP/1.1:Pipeling(流水線) 解決方式爲,若干個請求排隊串行化單線程處理,後面的請求等待前面請求的返回才能獲得執行機會。一旦有某請求超時等,後續請求只能被阻塞,毫無辦法,也就是人們常說的線頭阻塞。

  • HTTP/2:多個請求可同時在一個連接上並行執行。某個請求任務耗時嚴重,不會影響到其它連接的正常執行。

如下圖所示:

HTTP2.0 多路複用優點

HTTP 性能優化的關鍵並不在於高帶寬,而是低延遲。TCP 連接會隨着時間進行自我「調諧」,起初會限制連接的最大速度,如果數據成功傳輸,會隨着時間的推移提高傳輸的速度。這種調諧則被稱爲 TCP 慢啓動。由於這種原因,讓原本就具有突發性和短時性的 HTTP 連接變的十分低效。

HTTP/2 通過讓所有數據流共用同一個連接,可以更有效地使用 TCP 連接,讓高帶寬也能真正的服務於 HTTP 的性能提升。

服務器推送

服務端推送能把客戶端所需要的資源伴隨着 index.html 一起發送到客戶端,省去了客戶端重複請求的步驟。正因爲沒有發起請求,建立連接等操作,所以靜態資源通過服務端推送的方式可以極大地提升速度。具體如下:

  • 普通的客戶端請求過程:

  • 服務端推送的過程:

爲什麼需要頭部(header)壓縮?

假定一個頁面有 100 個資源需要加載(這個數量對於今天的 Web 而言還是挺保守的),而每一次請求都有 1kb 的消息頭(這同樣也並不少見,因爲 Cookie 和引用等東西的存在),則至少需要多消耗 100kb 來獲取這些消息頭。HTTP2.0 可以維護一個字典,差量更新 HTTP 頭部,大大降低因頭部傳輸產生的流量。

具體參考:《HTTP/2 頭部壓縮技術介紹》 文章。

  • 維護一份相同的靜態字典(Static Table),包含常見的頭部名稱,以及特別常見的頭部名稱與值的組合。

  • 維護一份相同的動態字典(Dynamic Table),可以動態地添加內容。

  • 支持基於靜態哈夫曼碼錶的哈夫曼編碼(Huffman Coding)。

參考與推薦如下文章:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章