HTTP全稱Hyper Text Transfer Protocol
,即超文本傳輸協議。HTTP是一個應用層協議,可視爲一個在計算機世界裏專門在兩點之間傳輸文字、圖片、音頻、視頻等超文本數據的約定和規範。面試
咱們這裏就直接以一個常見的面試題引入啦。算法
在瀏覽器中輸入 www.baidu.com 後會發生什麼?數據庫
當一個用戶在瀏覽器裏輸入 www.baidu.com
這個 URL 時,將會發生不少操做。首先它會請求 DNS 把這個域名解析成對應的 IP 地址,而後根據這個 IP 地址在互聯網上找到對應的服務器,向這個服務器發起一個GET 請求,由這個服務器決定返回默認的數據資源給訪問用戶。在服務器端實際上還有很複雜的邏輯:服務器可能有好多臺,到底指定哪臺服務器來處理請求,這須要一個負載均衡設備來平均分配全部用戶的請求;還有請求的數據是存儲在分佈式緩存裏仍是一個靜態文件中,或是在數據庫裏;當數據返回瀏覽器時,瀏覽器解析數據發現還有一些靜態資源(如 CSS、JS 或者圖片)時又會發起另外的 HTTP 請求,而這些請求有可能會在 CDN 上,那麼 CDN 服務器又會處理這個用戶的請求,大致上一個用戶請求會涉及這麼多操做。每個細節都會影響這個請求最終是否會成功。後端
咱們不去涉及其中過多的知識,單說HTTP的請求流程便可,從上面咱們知道,HTTP協議是由客戶端發起的,由請求和響應構成,是一個標準的客戶端服務器模型(C/S),它的具體流程以下:瀏覽器
地址解析。域名系統DNS解析域名獲得主機的IP地址;緩存
封裝HTTP請求數據包。封裝的內容有以上部分結合本機本身的信息;安全
封裝成TCP包,創建TCP鏈接(TCP的三次握手);服務器
客戶機發送請求命令。 創建鏈接後,客戶機向服務器發送一個請求;markdown
服務器響應。服務器接到請求後,給予相應的響應信息;網絡
服務器關閉TCP鏈接。通常Web服務器向瀏覽器發送了請求數據,它要關閉TCP鏈接;
客戶端解析報文。客戶端接收到響應報文後解析HTML代碼,並渲染。
HTTP常見的狀態碼分爲五大類,以下表所示:
狀態碼類別 | 具體含義 | 常見狀態碼 |
---|---|---|
1xx | 提示信息,表示目前是協議處理的中間狀態,還須要後續的操做 | |
2xx | 成功,報文已經收到並被正確處理 | 200、20四、206 |
3xx | 重定向,資源位置發生變更,須要客戶端從新發送請求 | 30一、30二、304 |
4xx | 客戶端錯誤,請求報文有誤,服務器沒法處理; | 400、40三、404 |
5xx | 服務器錯誤,服務器在處理請求時內部發生了錯誤。 | 500、50一、50二、503 |
1xx:1xx
類狀態碼屬於提示信息,是協議處理中的一種中間狀態,實際用到的比較少。
2xx:2xx
類狀態碼錶示成功處理了客戶端需求,也是咱們瀏覽器發起請求時常見的狀態:
HEAD
請求,服務器返回的響應頭都會有 body 數據;3xx:3xx
類狀態碼錶示客戶端請求的資源發生了變更,須要客戶端用新的 URL 從新發送請求獲取資源,也就是重定向:
注:301 和 302 都會在響應頭裏使用Location
,指明後續要跳轉的 URL,瀏覽器會自動重定向新的 URL。
4xx:4xx
類狀態碼錶示客戶端發送的報文有誤,服務器沒法處理,也就是錯誤碼的含義:
5xx:5xx
類狀態碼錶示客戶端請求報文正確,可是服務器處理時內部發生了錯誤,屬於服務器端的錯誤碼:
首先咱們瞭解一下HTTP的報文結構,大概以下:
這是常見的請求報文,固然還有響應報文,二者之間並不徹底一致,這裏只簡單說起一下請求報文的格式。
首先是請求方法,常見的請求方法有 GET和POST兩種,以後跟着的是URL,即要訪問的地址,再後面跟着的就是協議版本,如:HTTP/1.1。
咱們主要講解以後跟着的字段,即請求頭,請求頭的字段常以key-value
的形式,即」屬性名:屬性值「的形式傳遞若干數據,服務端據此獲取客戶端的信息。接下來咱們就來了解常見的字段:
Accept
字段與Content-type
字段:Accept字段用於客戶端向服務器發送報文時表示本身可接收的響應內容類型,如:Accept:text/plain
(文本類型);
相似的字段還有Accept-Charset
表示可接收的字符集;Accept-Encoding
表示可接受的響應內容的壓縮方式 ;Accept-Language
表示可接受的響應內容語言列表; Accept-Datetime
表示可接受的按照時間來表示的響應內容版本。
Content-Type字段用於服務器迴應時,告訴客戶端,本次數據的格式是什麼。
相似的字段還有Content-Encoding
字段表示數據的壓縮方法,表示服務器返回的數據使用什麼壓縮格式。
Host
字段
Host字段用於客戶端發送請求時,用來指定服務器的域名。例如:Host:www.baidu.com
。這裏須要與報文中的請求行的 URL 區分,Host字段與 URL 組成完整的請求URL,例如請求行中的URL爲/getPerson
,而Host字段爲www.baidu.com
,那麼二者結合起來就是www.baidu.com/getPerson
。
Connection
字段
Connection字段最經常使用於客戶端要求服務器使用 TCP 持久鏈接,以便其餘請求複用。
Connection: keep-alive
擴展:
HTTP是無狀態的面向鏈接的協議,無狀態並不表明HTTP不能保持TCP鏈接,HTTP使用的不是UDP(無鏈接);
HTTP/1.1 版本的默認鏈接都是持久鏈接,但爲了兼容老版本的 HTTP,須要指定Connection
首部字段的值爲Keep-Alive
。簡單的說,當一個網頁打開完成後,客戶端和服務器之間用於傳輸的 HTTP 數據的 TCP 鏈接不會馬上關閉,若是客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經創建的鏈接;
Keep-Alive不會永久保持鏈接,它有一個保持時間,能夠在不一樣的服務器軟件(如Apache)中設定這個時間。
Content-Length
字段
服務器在返回數據時,會有Content-Length
字段,代表本次迴應的數據長度。例如:Content-Length: 1000
,這代表了服務器本次迴應的數據長度是1000個字節,後面的字節就屬於下一個迴應了。
在 HTTP/1.0 中有很大的性能問題,每次發起一個HTTP請求,都須要去創建一次TCP鏈接,並且仍是串行請求,這使得 HTTP 在 TCP 的鏈接創建上花費了大量的開銷。對於這種問題,HTTP/1.1 中提出了長鏈接的通訊方式,也叫持久鏈接。這種鏈接的好處在於減小了 TCP 鏈接的重複創建和斷開所形成的額外開銷,減輕了服務器端的負載:
HTTP/1.1 採用了長鏈接的方式,這使得管道(Pipeline)網絡傳輸成爲了可能。便可在同一個 TCP 鏈接裏面,客戶端能夠發起多個請求,只要第一個請求發出去了,沒必要等其回來,就能夠發第二個請求出去,能夠減小總體的響應時間。
可是服務器仍是按照順序,先回應第一個請求,完成後再回應第二個請求,以此類推。要是前面的請求迴應得特別慢,後面就會有許多請求阻塞着,這就是所謂的【隊頭阻塞】。
因此 HTTP/1.0 或是 HTTP/1.1 性能都不是很完美,因此後續會有其餘增強。
HTTP的內容是明文傳輸的,明文數據會通過中間代理服務器、路由器、WIFI熱點、通訊服務運行商等多個物理節點,若是信息在傳輸過程當中被劫持,傳輸的內容久徹底暴露了,劫持者還能夠篡改傳輸的信息且不被雙方察覺,這就是中間人攻擊。
總結一下,HTTP在安全方面有如下三個問題:
針對上面咱們提到的HTTP的安全問題,HTTPS 在 HTTP 的基礎上增長了加密處理、認證機制和完整性保護,咱們能夠將 HTTPS = HTTP + 加密 + 認證 + 完整性保護;
由於 HTTP 使用明文傳輸,中間會通過多個物理節點,可能會被劫持竊聽,針對這一問題,HTTPS 採用了加密的方式解決。最容易理解的就是對稱加密。
對稱加密好理解,就是咱們擁有一個密鑰,它能夠用來對一段內容進行加密,一樣的,在內容被進行加密後,須要用同一個密鑰對加密內容進行解密,才能看到本來的內容,能夠看做咱們平常生活中的鑰匙。
HTTP 能夠直接使用對稱加密嗎?
固然不能夠。若是通訊雙方各自持有同一個密鑰,且沒有第三方知曉,那麼這兩方之間的通訊安全是能夠被保證的(畢竟密鑰被破解可能性不大)。問題是」如何使得這個密鑰可讓傳輸的雙方知曉,同時不被別人知道「?
假如咱們如今瀏覽器生成一個密鑰而後發送到服務端,告訴服務端咱們雙方用這個密鑰來加密傳輸文件。或者是放過來,由服務器生成密鑰而後發送給瀏覽器。很明顯這就不現實,咱們知道 HTTP 傳輸時中間是須要通過許多箇中間節點的,在通過中間節點時這個密鑰被劫持下來是一件十分容易的事,因此這種方式不可取。由此引入非對稱加密。
非對稱加密有兩把密鑰,一般一把叫作公鑰,另一把叫作私鑰。用公鑰加密的內容必須用私鑰才能解開,一樣的,私鑰加密的內容須要用公鑰才能解開。
HTTP 能夠直接使用非對稱加密嗎?
仍是不能夠。鑑於非對稱加密的性質,咱們可能會有這種思路:服務器先把公鑰直接明文傳輸給瀏覽器,以後瀏覽器向服務器傳數據前都先用這個公鑰加密好再傳輸,這條數據彷佛能夠保障了,由於只有服務器端的相應私鑰能解開這條數據。可是這樣仍是有問題,密鑰仍是能夠被劫持的。
若是服務器用它的的私鑰加密數據傳給瀏覽器,那麼瀏覽器用公鑰能夠解密它,而這個公鑰是一開始經過明文傳輸給瀏覽器的,若是這個公鑰被誰劫持到的話,他也能用該公鑰解密服務器傳來的信息了。因此這種方式的實現仍是會有問題,彷佛只能保證由瀏覽器傳輸數據時的安全性(其實還有漏洞)。
經過一組公鑰、私鑰已經能保證單個方向傳輸的安全性,那用兩組公鑰私鑰是否是就能保證雙向傳輸都安全了,如下面流程爲例:
這種實現方式理論上確實可行,拋開這裏面仍有的漏洞不談(下文再述),HTTPS 的加密卻沒有使用這種方案,爲何?
最主要的緣由是非對稱加密算法很是耗時,特別是加密解密一些較大數據的時候有些力不從心。相比之下,對稱加密就要快不少,那能不能同時運用對稱加密與非對稱加密的性質來實現對 HTTP 的加密呢?
既然非對稱加密耗時,那麼就用「對稱加密 + 非對稱加密」結合的形式來實現對 HTTP 的加密,並且還得儘可能減小非堆成加密的次數 ,這樣是否能實現呢?
這種方式是能夠實現的,並且非對稱加密、解密各只須要用一次便可。請看如下過程:
HTTPS 基本上就是採用了這種方案了,固然這種方法仍是有漏洞,咱們接着往下講。
根據上面的混合加密過程,中間人確實沒法擁有瀏覽器生成的對稱密鑰 X,這個密鑰自己就被公鑰 A 給加密了,只有服務器才能經過私鑰 A‘ 對其進行解密。然而在這個過程當中中間人徹底不須要獲取到密鑰 A’ 就能進行攻擊了。以下流程所示:
這樣在雙方都不會發生異常的狀況下,中間人獲得了密鑰 X,這其中的根本緣由就是瀏覽器沒法確認本身收到的公鑰是否是網站的。那麼接下來就是要解決這一問題。
如何證實瀏覽器收到的公鑰必定是該網站的公鑰?這裏就須要有一個公信機構給網站頒發一個「身份證」了。網站在使用 HTTPS 前,須要向「CA機構」申請頒發一份數字證書,數字證書裏有證書持有者、證書持有者的公鑰等信息,服務器把證書傳輸給瀏覽器,瀏覽器從證書裏取公鑰就好了,證書就如同身份證同樣,能夠證實「該公鑰對應該網站」。
然而到這裏仍是有一個問題,如何保證證書在傳輸的過程不會被篡改,身份證自己有防僞的技術,那麼如何保證證書的防僞呢?
如何保證證書不被篡改?
咱們把證書內容生成一份「簽名」,比對證書內容和簽名是否一致就能察覺是否被修改,這種技術就稱爲數字簽名;
數字簽名的製做過程?
將明文和數字簽名共同組成數字證書,這樣一份證書就能夠頒發給網站了。
瀏覽器獲得證書後如何驗證這份證書的真實性?
瀏覽器如何獲得權威機構的公鑰?
上面提到,如何要對服務器發過來的證書進行解密,那麼就須要到CA的公鑰,由於其被CA的私鑰給加密了。那麼瀏覽器是如何擁有CA的公鑰呢?
實際上權威機構的公鑰並不須要傳輸,由於權威機構會和主流的瀏覽器或操做系統合做,將他們的公鑰內置在瀏覽器或操做系統環境中。客戶端收到證書以後,只須要從證書中找到權威機構的信息,並從本地環境中找到權威機構的公鑰,就能正確解密A公鑰。固然實際狀況要比這個複雜得多,這裏簡單介紹就行。
中間人有可能篡改證書嗎?
上面咱們提到,權威機構的公鑰是可能在瀏覽器或操做系統中的,那麼中間人劫持到證書後是能夠解密獲得原文的。相應的,他也能夠去篡改證書的原文,可是因爲他沒有 CA 機構的私鑰,沒法相應地篡改簽名。因此瀏覽器收到證書後會發現原文和解密後的值不一致,說明證書已經被篡改,證書不可信了,因此中間人不可能去篡改證書了。
client key
,即客戶端密鑰,這樣在概念上和服務器端的密鑰容易進行區分。而後用服務器的公鑰對客戶端密鑰進行非對稱加密,這樣客戶端密鑰就變成密文了,至此,HTTPS中的第一次HTTP請求結束;文章內容絕大數來源網絡,我只是個搬運工,如有哪裏出錯,請評論區指出。
參考資料: