這是一份關於HTTP協議的學習總結

前言

隨着互聯網的發展,網絡已經愈來愈普及了,絕大多數的網絡請求都是基於HTTP協議的,所以在開發中,瞭解HTTP的基本原理是必要的,在TCP/IP四層體系結構中,HTTP協議位於應用層,它是應用層主要使用的協議,應用層往下一層就是運輸層,HTTP在運輸層採用的是TCP協議來保證可靠傳輸,知道這些後,接下來詳細介紹一下 Http。html

1、HTTP協議版本演變

咱們先來簡單瞭解一下 HTTP 協議的歷史演變:git

  • HTTP/1.0:1996年,HTTP/1.0 版本發佈,能夠傳輸文字,圖像、視頻、二進制文件,它的特色是每次請求都須要創建一個單獨的TCP鏈接,發送數據完畢,鏈接就關閉,若是還要請求其餘資源,就必須再新建一個鏈接,上一次請求和下一次請求徹底分離,這種非持續鏈接過程又叫作短鏈接。它的特色也是它的缺點,客戶端和服務端每次請求都要創建TCP鏈接,而創建TCP鏈接和關閉TCP鏈接都是相對比較費時的過程,嚴重影響客戶端和服務端的性能。
  • HTTP/1.1:1997年,HTTP/1.1 版本發佈,1999年普遍應用於各大瀏覽器網絡請求中,直到如今HTTP/1.1也是使用最爲普遍的HTTP協議,它進一步完善了HTTP/1.0,HTTP/1.1支持在一個TCP鏈接上傳送多個HTTP請求和響應,即一個TCP鏈接能夠被多個請求複用,減小了創建和關閉鏈接的消耗延遲,必定程度上彌補了HTTP/1.0每次請求都要建立鏈接的缺點,這種持續鏈接過程又叫作長鏈接,HTTP/1.1默認使用長鏈接。
  • HTTP/2.0:2015年,HTTP/2 .0版本發佈,前面的兩個版本都是基於超文本的協議,HTTP 2.0把基於超文本的協議改爲了基於二進制的,把HTTP請求和響應變成數據幀,這樣易於實現多路複用,在一個TCP鏈接上能夠同時「混合」發送多個HTTP的請求和響應,效率大大提升。

長鏈接和多路複用的區別算法

上面講到HTTP/1.1的長鏈接和HTTP 2.0的多路複用都是複用TCP鏈接,它們之間有什麼區別呢?在講解它們的區別以前先來聊一聊HTTP/1.1的長鏈接,HTTP/1.1的長鏈接能夠分爲非流水線和流水線工做方式:數據庫

  • 非流水線:在同一個TCP鏈接下,客戶端的下一個請求只有收到當前請求的響應後才能發出;
  • 流水線:又稱Pipelining、管道化,在同一個TCP鏈接下,客戶端能夠連續的發送請求,而不用等待響應返回,當請求一個接着一個到達服務器時,服務器可以連續發回響應;

如圖:api

因此你會發現非流水線工做方式的長鏈接的若干個請求只能排隊發送,後面的請求等待前面請求的響應返回才能得到執行機會,一旦有某請求處理超時,後續請求只能被阻塞,這樣會致使TCP鏈接空閒,浪費資源;而流水線工做方式的長鏈接就能夠連續的發送多個請求而沒必要等待響應的返回,這樣看起來效率提升了一些。瀏覽器

因此流水線工做方式就是好的嗎?這裏根據我查到的資料是:Pipelining在現代瀏覽器中是默認關閉的,由於因爲技術和安全的關係,實現Pipelining在HTTP/1.X上是很複雜,同時Pipelining技術不支持全部的請求方法,並且就算開啓了,因爲隊頭阻塞的存在,它的效率也不會提升多少,假設多個請求按順序 (現實狀況可能因爲網絡擁堵不會按順序到達) 到達服務端,多個請求會在服務端緩存那邊排隊,若是第一個請求處理時間過長,會致使後面的請求阻塞,並且頗有可能後面有優先級更高的請求,這樣致使高優先級請求不能被優先處理,因此無論有沒有流水線工做方式,請求仍是要排隊處理,隊頭阻塞仍是存在,流水線工做方式只能說是對非流水線方式的一種改進。緩存

那麼就沒有辦法提升響應效率了嗎?爲了解決這些問題,HTTP1.x支持在同一個域名(host)下創建多個TCP鏈接,現代瀏覽器支持同時創建5~10個TCP鏈接,即支持並行發送請求,每一個瀏覽器都有一個Max-Connection最大鏈接限制,例如谷歌瀏覽器的Max-Connection值爲6,即同一個域名下最多創建6個TCP鏈接,一次最多同時發送6個請求,超過限制後續請求就會被阻塞。安全

因此,綜上所述,因爲Pipelining技術在瀏覽器中默認是關閉的,因此HTTP1.1長鏈接的工做方式是非流水線形式,爲了實現並行發送請求只能經過創建多個TCP鏈接,這在HTTP1.x時代中已經很不錯了,可是隨着技術的發展,如今一個網站每秒簡簡單單就上百個請求,而頻繁的創建和保留TCP鏈接又是一件工做量不小的工做,因此並行TCP鏈接帶來的效率有時也會很低。服務器

因此爲了解決以上全部問題,HTTP/2.0就誕生了,HTTP/2.0的多路複用(multiplexing)纔是作到了同一個TCP鏈接下的真正的併發請求,多個請求可同時在一個TCP鏈接上並行發送,某個請求任務超時,不會影響到其它鏈接的正常執行,並且每一個請求均可以分配優先級,優先級高的先執行。cookie

如圖:

HTTP/2.0從協議的層面改進了HTTP,是將來的應用,對於HTTP2.0的更多優勢能夠查看HTTP2.0新特性, 因爲HTTP/2.0還未大規模應用,因此下面的討論都是圍繞HTTP/1.x

HTTP1.1的長鏈接在瀏覽器中是默認開啓的,經過指定首部Connection:Keep-Alive,後面會講到長鏈接的工做原理。

2、HTTP工做過程

HTTP是基於TCP的應用層協議,從更高層次封裝了TCP的使用細節,使得網絡操做更爲簡單,一個HTTP請求就是一個典型的C/S模式,HTTP協議首先要和服務端創建TCP鏈接,當創建TCP鏈接的三報文握手的前兩次報文握手完成後,在第三次握手,客戶端就把HTTP請求報文做爲第三個握手報文的數據發送給服務端,服務端收到請求報文後,就把所請求的文檔做爲響應報文返回給客戶端,以下:

HTTP的工做特色能夠總結爲如下3點:

  • 一、面向無鏈接的:即通訊雙方在交換HTTP報文時不須要向創建HTTP鏈接,但HTTP使用了面向鏈接的TCP做爲運輸層協議;
  • 二、無狀態的:服務端不會記得每一個客戶訪問的狀態,同一個客戶訪問兩次服務端上的頁面時,服務端響應與第一次訪問相同,因此出現了Cookie/Session機制維護鏈接的狀態;
  • 三、面向事務的:即對一系列信息的交換,要麼全部信息交換都完成,要麼一次交換都不進行。

3、HTTP的請求方法

HTTP協議提供了幾種請求方式,你們熟知的請求方式有8種GET、POST、DELETE、PUT、HEAD、TRACE、OPTIONS、CONNECT,其中最經常使用的是PUT(增)、DELETE(刪)、POST(改)、GET(查)。下面以一張表來看看它們各自的做用。

請求 做用
GET 獲取資源:客戶端經過URL獲取服務端中的某個資源,請求參數放在URL中,而後服務端返回對應資源給客戶端
POST 傳輸實體主體:POST請求一般會用來提交HTML表單,把數據填在表單中,傳給服務器,而後服務器對這些數據進行處理,雖然GET方法也能夠用來傳輸主體實體,可是通常採用POST方法
PUT 傳輸文件:與GET相反,PUT向服務器寫入數據,通常用來傳輸文件,把須要傳輸的文件放在請求報文的主體上,而後保存到URL指定的位置
DELETE 刪除文件:與PUT相反,DELETE請求求服務器刪除URL所指定的資源,請求參數放在URL中,可是服務端能夠在客戶端不知情下撤銷此請求
HEAD 獲取報文首部:HEAD與GET相似,但服務器在響應中只返回首部不會返回主體部分,HEAD是用來在不獲取資源的狀況下獲取資源的首部進行檢查,如查看響應的狀態碼,看看資源是否被修改,對象是否存在
TRACE 追蹤路徑:客戶端發起一個請求時,可能要穿過防火牆,代理,網關等,每個中間點都會修改HTTP原始請求報文,TRACE容許請求最終發送給服務端時,看看它最終變成什麼樣,服務端會返回一個狀態碼200 OK的響應報文,報文主體包含了TARCE信息
OPTIONS 詢問支持的方法:OPTIONS詢問服務端支持的用來查詢指定URL資源的方法,這就讓客戶端不用訪問那些實際的資源就能斷定訪問各類資源的最優方法
CONNECT 要求使用隧道協議鏈接代理:CONNECT要求在與代理服務器通訊時創建隧道,實現用隧道進行TCP通訊,隧道就是通過加密的通訊信路,通常使用SSL/TLS協議把通訊內容加密後經隧道傳輸

HTTP/1.0支持的方法有:

GET、POST、PUT、HEAD、DELETE;

HTTP/1.1新增的方法有:

OPTIONS、TARCE、CONNECT。

代理服務器:代理服務器是一種具備轉發功能的服務器,它扮演了服務器和客戶端之間的中間人角色,它能夠接收客戶端發來的請求並轉發給服務端,也能夠接收服務端返回的響應並轉發給客戶端,在這個過程當中它不會改變任何URL,報文每通過一個代理服務器,都須要在首部via字段的末尾插入一個能夠表明代理服務器的獨特的字符串, 代理服務器主要做用有:緩存代理(減小網絡帶寬)、訪問控制(提升安全性)等。

4、HTTP的報文格式

用於HTTP協議交換的信息稱爲HTTP報文,客戶端發出的HTTP報文叫作請求報文,服務端返回的HTTP報文叫作響應報文,它們都是由多行數據構成的字符串文本,用CR + LF (回車符 + 換行符) 做爲換行符,HTTP報文大致分爲報文首部報文主體兩塊,由第一個出現的空行(CR + LF)劃分,其中報文主體不是必須的,以下:

其中報文首部又能夠分爲:開始行、首部行;開始行根據報文的不一樣又分爲:請求行、狀態行;首部行根據報文的不一樣與首部字段的做用又能夠分爲:請求首部字段、響應首部字段、通用首部字段、實體首部字段。

下面分別簡單介紹一下HTTP的請求報文和響應報文:

一、請求報文

一個HTTP的請求報文一般由請求行,請求首部,空行(CR + LF),請求主體4個部分組成,如圖:

  • 請求行

    又叫起始行,就是報文的第一行,在請求報文中說明要以什麼方式作什麼請求;

  • 請求首部

    又叫首部,在請求行以後,由零個或多個首部字段組成,每一個字段包含一個key和value,用冒號 : 分割,如Connection:keep-Alive,每一個首部字段以一個CR + LF結束;

  • 請求主體

    又叫主體,其中能夠包含任意類型的數據,如圖片,視頻、文本等,而請求首部和請求行只能是文本形式,在請求主體中包括了要發送給Web服務端的數據。

不一樣的請求方式,它們的請求報文格式可能有點差異的,有些請求方式它的請求主體爲空,有些則不爲空,可是請求行和請求首部是必須存在的,下面以GET、POST請求報文舉例:

1.一、GET的請求報文

對於GET方法來講,它全部的請求參數都是拼接在URL最後,第一個參數前經過"?"鏈接,而後請求參數按照"key=value"格式進行追加,每一個請求參數之間經過"&"鏈接,如 :

www.myhost.com/text/?id=1&…

這個URL對於GET請求表示獲取 www.myhost.com/text/ 位置下用戶id爲1名爲rain的文本,相應的請求報文格式以下:

GET /text/?id=1&name=rain HTTP/1.1
Host: www.myhost.com
Cache-Control: no-cache
複製代碼

從上面的HTTP請求報文格式知,第一行爲請求行,代表請求方式爲GET,子路徑爲 /text/?id=1&name=rain,HTTP版本爲1.1,後兩行爲請求首部,Host爲主機地址,Cache-Controlno-cache,表示客戶端不接受服務端緩存過的資源,而GET的請求參數都在URL中,因此請求主體爲空。

注意:對於URL的最長長度,不一樣的瀏覽器又不一樣的限制,大約爲1024字節(1KB)。

1.二、POST的請求報文

對於POST方法來講,它們的報文格式通常是表單格式,也就是說請求參數存儲在請求主體位置上,以下:

POST /local/ HTTP/1.1
Host: www.myhost.com
Accept-Encoding:gzip
Content-Length: 222222
Content-Type: multipart/from-data;boundary=dRGP2cPPTxE6WRTssnh4jC7HJLcSde
Connection:Keep-Alive

--dRGP2cPPTxE6WRTssnh4jC7HJLcSde
Content-Disposition:from-data;name=「username」  //name = username
Content-Type:text/plain:charset=UTF-8
Content-Transfer-Encoding: 8bit

rain										//value = rain
--dRGP2cPPTxE6WRTssnh4jC7HJLcSde
Content-Diaposition:from-data:name="image"      //name = image
filename="/storage/emulated/0/image/1234.png"
Content-Type:application/octet-stream
Content-Transfer-Encoding:binary

//...省略二進制數據					        //value = 二進制數據
--dRGP2cPPTxE6WRTssnh4jC7HJLcSde--
複製代碼

上述的請求報文的含義是向 www.myhost.com/local/ 這個地址發送一個POST請求,接受的內容編碼方式爲gzip,請求的數據長度爲222222字節,請求的數據格式爲 multipart/from-data(表單),報文的boundary值爲dRGP2cPPTxE6WRTssnh4jC7HJLcSdeKeep-Alive爲開啓長鏈接,空行以後,接下來就是請求報文的主體,主體有兩個請求參數:

一個是名爲username值爲rain的文本;

一個是名爲image值爲二進制數據的圖片.

請求參數是以兩橫槓+boundary開始的,而後是請求參數的一些首部,又稱實體首部字段,如參數名,格式等,而後加上一個空行,最後纔是參數的值,如上述的username=name,其表示以下:

--dRGP2cPPTxE6WRTssnh4jC7HJLcSde		       //兩橫槓加boundary做爲參數的開始
Content-Disposition:from-data;name=「username」 //name = username
Content-Type:text/plain:charset=UTF-8
Content-Transfer-Encoding: 8bit
						                    
rain						                 //value = rain
複製代碼

當報文主體中包含多個參數時,都要遵照這種格式:每一個參數以兩橫槓+boundary分隔,參數首部字段與值之間有一個空行

請求主體的最後是以兩橫杆+boundary+兩橫槓做爲整個報文的結束符,如上面報文的最後一個參數 (圖片二進制數據) 最後的**- -dRGP2cPPTxE6WRTssnh4jC7HJLcSde- -**,以下:

--dRGP2cPPTxE6WRTssnh4jC7HJLcSde			 //兩橫槓加boundary做爲參數的開始
Content-Diaposition:from-data:name="image"    //name = image
filename="/storage/emulated/0/image/1234.png" 
Content-Type:application/octet-stream
Content-Transfer-Encoding:binary
										  //不可省略的空行
//...省略二進制數據						  //value = 二進制數據
--dRGP2cPPTxE6WRTssnh4jC7HJLcSde--	          //整個報文的結束符
複製代碼

二、響應報文

一個HTTP的響應報文一般由狀態行、響應首部、空行(CR + LF)、響應主體組成,以下:

  • 狀態行

    在響應報文中粗略的說明了報文的執行結果;

  • 響應首部

    又叫首部,在狀態行以後,由零個或多個首部字段組成,每一個字段包含一個key和value,用冒號 : 分割,每一個首部以一個CR + LF結束;

  • 響應主體

    其中能夠包含任意類型的數據,如圖片,視頻、文本等,而首部和狀態行只能是文本形式,在響應主體中包含了服務端要返回給客戶端的數據.

能夠看到響應報文與請求報文的格式相似,最大的不一樣的就是第一行用狀態信息代替了請求信息,格式以下:

HTTP-Version Status-Code Reason-Phrase CRLF
複製代碼

其中HTTP-Version表明HTTP協議版本,Status-Code表明響應狀態碼,Reason-Phrase表明狀態碼的文本描述,其中狀態碼的5種取值範圍以下:

取值範圍 含義
100~199 信息狀態碼,表示請求已被接收,正在處理
200~299 成功狀態碼,表示請求已被成功處理
300~399 重定向狀態碼,表示完成請求必需要進行進一步的操做
400~499 客戶端錯誤狀態碼,表示客戶端請求有語法錯誤或請求沒法實現
500~599 服務端錯誤狀態碼,表示服務端處理請求時出錯

例如這是一個GET請求的返回的響應報文格式:

HTTP1.1 200 OK
Data:Sat, 30, Dec 2006 23:23:00 GMT
Content-Type:text/html;charset=UTF-8
Content-Length:852

<!DOCTYPE html>
<html lang="zh-CN">
	//...省略文檔內容
</html>
複製代碼

上面HTTP響應報文表示,HTTP協議版本爲1.1,響應狀態碼爲200,表示請求成功,返回數據的類型爲text/html(html), 編碼爲UTF-8,返回數據的內容長度爲852字節,空行以後,接下來就是返回的數據,是一個html文檔。

5、常見的狀態碼

狀態碼的職責是當客戶端向服務端發送請求時,描述服務端返回的請求結果,藉助狀態碼,咱們就能夠得知服務端是正常處理了請求,仍是出現了錯誤,下面是開發中常常碰見的狀態碼:

一、2XX成功

2XX的響應結果表示請求被正常處理了.

  • 200 OK:該狀態碼錶示從客戶端發來的請求在服務端被正常處理了,在返回的響應報文中,隨狀態碼返回的信息會由於請求方法的不一樣而不一樣。例如GET方法,響應報文的主體會包含請求的資源,而對於HEAD方法,響應報文不包含主體部分,只包含響應首部;
  • 204 No Content:該狀態碼錶示服務端接收的請求已成功處理,可是在返回的響應報文中不包含主體部分,這說明請求處理成功,可是沒有任何資源返回。好比當瀏覽器發出的請求處理後,返回204響應,那麼瀏覽器顯示的頁面將不會發生任何更新;
  • 206 Partial Content: 該狀態碼錶示客戶端進行了範圍請求,而服務端成功返回了這一部分範圍的資源,即響應報文的主體部分中會包含由Content-Range指定範圍的內容。

二、3XX重定向

3XX的響應結果表示客戶端須要執行某些特殊操做後,服務端才能繼續處理請求.

  • 301 Moved Permanently:永久性重定向,該狀態碼錶示請求的資源已被分配了新的URL,之後都應使用新的URL來訪問該資源,這時響應報文首部的Location字段會提示新的URL。例如你使用這個最後忘記加斜槓 / 的地址 www.myhost.com 來訪問服務端,就會返回301狀態碼,提示你使用正確的地址訪問,不過這些重定向的操做瀏覽器在背後已經替咱們處理了,因此用戶是沒法感知的;
  • 302 Found:臨時重定向,該狀態碼錶示請求的資源暫時被分配了新的URL,本次應使用新的URL來訪問該資源,302和304的區別就是一個是臨時性,一個是永久性,302表明資源不是被永久移動,而是臨時移動,即本次會重定向到地址a,下一次可能會重定向到地址b或者不變,因此響應報文首部的Location字段提示的新URL並非永久性的,而是臨時性的;
  • 303 See Other:臨時重定向,該狀態碼錶示請求的資源暫時被分配了新的URL,本次應使用新的URL經過GET方法來訪問該資源,303和302功能類似,可是303明確表示客戶端重定向時應採用GET方法獲取資源,而302就沒有這個要求。(可是在現實中,大部分瀏覽器都沒有遵循規範,無論是30一、302仍是303,都會把POST改爲GET,而後從新獲取資源);
  • 304 Not Modified:304雖然被劃分在3XX中,可是它和重定向沒有任何關係,該狀態碼錶示客戶端訪問的資源存在,可是未符合請求的附帶條件,不允返回,這時返回的304響應報文不包含主體部分,請求的附帶條件是指請求報文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部。例如客戶端想要檢查本地資源緩存是否過時,就在GET請求中附帶If-Modified-Since條件,If-Modified-Since的值是本地資源的Last-Modified(上一次修改時間)的值,服務端接收請求後,就會檢查資源在服務端的上一次修改的時間是否比If-Modified-Since的值更新,若是沒有,說明資源沒有被修改過,返回304響應報文,告訴客戶端能夠繼續使用本地緩存。(關於HTTP的緩存機制能夠查看HTTP 協議緩存機制詳解 )。

三、4XX客戶端錯誤

4XX的響應結果表示客戶端發生錯誤的緣由所在.

  • 400 Bad Request:該狀態碼錶示客戶端的請求報文中有語法錯誤,不能被服務端理解,當發生該錯誤後須要修改請求內容後再次發送;
  • 401 Unauthorized:該狀態碼錶示發送的請求須要有經過HTTP認證的認證信息,401的響應報文會包含一個被請求資源的WWW-Authenticate首部用來質詢用戶信息,當瀏覽器初次接收到401響應,會彈出認證窗口,當瀏覽器第二次收到401響應,表示認證失敗;
  • 403 Forbidden:該狀態碼錶示服務端收到了請求,可是拒絕提供服務,服務端不會給出拒絕的詳細理由,例如沒有文件的訪問權限等都會返回404響應;
  • 404 Not Found:該狀態碼錶示請求資源在服務端上不存在,或者服務端拒絕請求但不想說明理由也會返回404;

四、5XX服務端錯誤

5XX的響應結果表示服務端發送錯誤的緣由所在.

  • 500 Internal Server Error:該狀態碼錶示服務端執行請求時發生了不可預估的錯誤,它代表服務端Web應用存在bug或其餘故障;
  • 503 Server Unavailable:該狀態碼錶示服務端當前不能處理客戶端請求,一段時間後可能恢復正常,它代表服務端暫時處於超負載或停機維護狀態,若是服務端得知故障恢復時間,它會在響應報文的Retry-After首部字段寫入返回給客戶端。

更多狀態碼信息請訪問HTTP狀態碼

6、常見的首部字段

下面列舉了HTTP/1.1中的47種常見首部字段,分爲通用首部字段、請求首部字段、響應首部字段、實體首部字段:

一、通用首部字段

表示請求報文和響應報文雙方都會使用的首部。

首部字段名 說明
Cache-Control 控制緩存的行爲
Connection 容許客戶端和服務端指定與請求/響應鏈接相關的選項
Date 建立報文的日期時間
Pragma 報文指令
Trailer 報文末端的首部一覽
Transfer-Encoding 告知接收端爲了保證報文的可靠傳輸性,對報文采用了什麼的編碼方式
Upgrade 升級爲其餘協議
Via 代理服務器的相關信息
Warning 錯誤通知

二、實體首部字段

表示請求報文和響應報文的主體的實體部分使用的首部,主要做用是補充資源內容的更新時間與實體相關的信息,能夠看到大多都是以Content開頭的。

首部字段名 說明
Allow 資源可支持的 HTTP 方法
Content-Encoding 實體主體適用的編碼方式
Content-Language 實體主體的天然語言
Content-Length 實體主體的大小
Content-Location 替代對應資源的 URI
Content-MD5 實體主體的報文摘要
Content-Range 實體主體的位置範圍
Content-Type 實體主體的媒體類型
Expires 實體主體過時的日期時間
Last-Modified 資源的最後修改日期時間

三、請求首部字段

表示從客戶端向服務端發送請求報文時使用的首部,主要做用是補充請求的附加內容、客戶端信息、響應內容相關優先級、編碼等信息。

首部字段名 說明
Accept 客戶端可識別的內容類型列表
Accept-Charset 客戶端可識別的字符集
Accept-Encoding 客戶端可識別的數據編碼
Accept-Language 客戶端可識別的語言(天然語言)
Authorization Web 認證信息
Expect 期待服務器的特定行爲
From 用戶的電子郵箱地址
Host 請求的主機名
If-Match 比較實體標記(ETag)
If-Modified-Since 比較資源的更新時間
If-None-Match 比較實體標記(與 If-Match 相反)
If-Range 資源未更新時發送實體 Byte 的範圍請求
If-Unmodified-Since 比較資源的更新時間(與 If-Modified-Since 相反)
Max-Forwards 最大傳輸逐跳數
Proxy-Authorization 代理服務器要求客戶端的認證信息
Range 實體的字節範圍請求
Referer 對請求中 URI 的原始獲取方
TE 傳輸編碼的優先級
User-Agent 發出請求的瀏覽器類型,能夠自行設置

四、響應首部字段

表示服務端向客戶端返回響應報文時使用的首部,主要做用是補充響應的附加內容、要求客戶端附加額外的內容等信息

首部字段名 說明
Accept-Ranges 是否接受字節範圍請求
Age 推算資源建立通過時間
ETag 資源的匹配信息
Location 令客戶端重定向至指定 URI
Proxy-Authenticate 代理服務器對客戶端的認證信息
Retry-After 對再次發起請求的時機要求
Server HTTP 服務器的安裝信息
Vary 代理服務器緩存的管理信息
WWW-Authenticate 服務器對客戶端的認證信息

下面列舉幾個對HTTP首部的常見使用。

五、具體應用

5.一、 長鏈接原理

從HTTP/1.1起,默認都開啓了長鏈接保持鏈接特性,經過在首部指定Connection:Keep-Alive,Keep-Alive也是一個首部,簡單地說,當一個網頁打開完成後,客戶端和服務端之間用於傳輸HTTP數據的TCP鏈接不會關閉,若是客戶端再次訪問這個服務端上的網頁,會繼續使用這一條已經創建的TCP鏈接,Keep-Alive不會永久保持鏈接,它有一個保持時間,能夠在不一樣服務端軟件中設置這個時間。

那麼,長鏈接是如何工做的呢?長短鏈接是運輸層(TCP)的概念,HTTP是應用層協議,它只能說告訴運輸層我打算一段時間內複用TCP通道,而沒有本身去創建、釋放TCP通道的能力,那麼HTTP是如何告訴運輸層複用TCP通道的呢?分爲如下幾個步驟:

  • 一、客戶端第一次發送請求報文時,順帶發送一個Connection: Keep-Alive的Header,表示須要保持鏈接,同時客戶端能夠順帶發送Keep-Alive: timeout=5, max=100這個Header給服務端;
  • 二、而後服務端識別Connection: Keep-Alive這個Header,而且經過響應報文Header帶一樣的Connection: Keep-Alive,告訴客戶端我能夠保持鏈接;
  • 三、客戶端和服務端之間經過保持的TCP鏈接收發數據;
  • 四、當客戶端最後一次發送請求報文,順帶發送Connection:close這個Header,表示長鏈接關閉。

Keep-Alive: timeout=5,max=100表示TCP鏈接空閒時最多保持5秒,長鏈接接受100次請求就斷開,長鏈接雖好,可是長時間的TCP鏈接容易致使系統資源無效佔用,浪費系統資源,因此須要有一些限制。

Connection首部除了用於管理鏈接外,還能控制再也不轉發的首部,格式爲:Connection: 再也不轉發的首部,當通過代理服務器時,代理服務器會把Connection首部字段中指定的首部刪除後,再把報文轉發給服務端。

5.二、內容協商

一個網站在服務器中可能有多種語言版本、有多份相同內容的頁面,例如英文版的網頁和中文版的網頁,在HTTP通訊時客戶端與服務端進行內容協商,讓服務端返回最合適的內容給客戶端,內容協商會以類型、字符集、編碼、語言等方式爲標準返回合適的響應資源。

客戶端能夠在請求報文中設定特定的Accept-XX首部字段,例如 Accept、Accept-Charset、Accept-Encoding、Accept-Language等,服務端根據這些字段返回特定的資源,這些字段的解釋以下:

  • Accept

    示例:Accept: text/html,image/jepg;q=0.8,video/mpeg;q=0.5,*/*;q=0.1

    客戶端在Accept首部中列舉了它支持的內容類型,服務端從這些內容類型中挑選出一個優先級最高的類型,返回這個類型的內容給客戶端,內容類型通常是type/subtybe形式,例如文本類型text/html、text/plain、...,圖片類型image/jepg、image/gif、...,視頻類型video/mpeg、...,等,多個類型之間用逗號 , 分隔,能夠用 * 通配符表示接受全部類型,經過q表示優先級,與類型用分號 ; 分隔, q值越大,優先級越高,q值得範圍是(0~1),若是不指定優先級,默認優先級都是1.0,內容類型放置順序按優先級排序;

  • Accept-Charset

    示例:Accept-Charset: iso-8859,unicode-1-1;q=0.5

    客戶端在Accept-Charset首部中列舉了它支持的字符集,服務端從這些字符集中挑選出一個優先級最高的字符集,返回這個字符集的內容給客戶端,與Accept相同,能夠經過q指定字符集的優先級,而且和Accept同樣,字符集的放置順序按優先級排序;

  • Accept-Encoding

    示例:Accept-Encoding: gzip,compress,deflate;q=0.5

    客戶端在Accept-Encoding首部中列舉了它支持的內容壓縮格式,服務端從這些內容壓縮格式中挑選出一個優先級最高的,把響應內容用這種格式壓縮後再返回給客戶端,客戶端收到壓縮的內容後,用相應的解壓算法解壓內容,再顯示出來,與Accept相同,能夠經過q指定優先級,經過 * 通配符表示支持任意壓縮格式;

  • Accept-Language

    示例:Accept-Language: zh-cn,en-us;q=0.5

    客戶端在Accept-Language首部中列舉了它支持的語言,服務端從這些語言中挑選出一個優先級最高的,返回相應語言版本的內容給客戶端,若是沒有優先級最高的語言版本,就返回次優先級的語言版本,例如示例中,沒有中文版時,就返回英文版。

當服務器從各類選擇列表中挑選出客戶端支持的類型、字符集、編碼、語言後,就會在響應報文的首部指定Content-XX首部字段,告訴客戶端響應內容的類型、字符集、編碼、語言,例如Content-Type、Content-Encoding、Content-Language等,Content-Type表示內容類型,還會指明內容的字符集,Content-Encoding表示內容的編碼類型,Content-Language表示內容的語言。

上述的內容協商叫作服務器驅動協商,即由客戶端經過首部告訴服務端它支持的東西,而後服務端作出選擇,可是對於用戶來講,瀏覽器替咱們作的決定不必定是最優的,例如我看不懂英文,瀏覽器根據代理地理位置作了判斷,返回了英文版的內容,這然對用戶來講不是最優的,因此還有一種叫作客戶端驅動協商,由用戶告訴服務端他想要什麼類型的內容,這時瀏覽器會彈出選擇列表讓用戶選擇,用戶選擇後,瀏覽器把用戶的選擇填入Accept-XX首部,再發送給服務端。

5.三、Cookie機制

Cookie是用來管理客戶端和服務端之間的狀態,它是服務器發送到客戶端並保存在本地的小型文本文件,其內容爲一系列的鍵值對,Cookie並不屬於HTTP/1.x的規範,可是因爲HTTP的無狀態特性,Cookie被普遍應用於各大Web網站的狀態管理及用戶識別。

Cookie的工做過程主要使用到了Set-CookieCookie這兩個首部,Set-Cookie首部存在於響應報文中,Set-Cookie首部包含服務端返回給客戶端狀態管理使用的Cookie信息,客戶端收到響應後會從Set-Cookie首部中取出Cookie信息保存到本地;Cookie首部存在於請求報文中,Cookie首部包含客戶端從服務端接收到的Cookie信息,每次客戶端發起請求時,都會在請求報文的Cookie首部中攜帶Cookie信息發送給服務端。

Cookie須要和服務端的Session配合使用,Cookie是存儲在客戶端中,而Session是存儲在服務器端中,Session是服務端保存用戶狀態的方式,它們的工做過程大概以下:

  • 一、當用戶登錄網站時,填入帳號、密碼等信息,而後提交表單,這些信息會被放入HTTP的請求報文,而後發送給服務端;
  • 二、服務端收到請求後,驗證該用戶名和密碼,若是正確,則爲該用戶建立一個Session對象,Session對象中保存了用戶的狀態信息,並生成Session對象的惟一ID,稱爲Session ID,而後把Session對象存儲到內存或數據庫中,根據Session ID根據從內存或數據庫獲取到Session對象;
  • 三、接着服務端把Session ID的值以name=value的形式放入響應報文的Set-Cookie首部中,其中name爲Session ID的名字,value就是Session ID的值,name=value形式的Session ID就稱爲Cookie,Set-Cookie首部除了Session ID以外,還有一些其餘信息,如Cookie的有效期、Cookie的域名範圍等,而後把這個響應報文發送給客戶端;
  • 四、客戶端收到響應報文以後從Set-Cookie首部中取出全部Cookie信息,而後把它保存到本地,客戶端有時候會收到不止一個Set-Cookie首部,若是有多個,每一個Set-Cookie首部中的Cookie信息都要保存;
  • 五、客戶端以後對同一個服務端進行請求時都會從本地取出Cookie信息,這時能夠校驗Cookie的有效期、路徑、域名等信息,而後取出其中的Cookie值放入請求報文的Cookie首部字段,若是有多個Cookie值,Cookie首部中就用 ; 分隔,而後把這個請求報文發送給服務端;
  • 六、服務器收到請求後,從Cookie首部中取出Cookie,從Cookie中取出Session ID,而後用Session ID從內存或數據庫取出用戶信息,恢復用戶以前的操做狀態。

下面是我登錄掘金時在響應報文找到的Set-Cookie首部,以下:

HTTP/1.1 200 OK
//...省略不少首部
Set-Cookie: ab={}; path=/; expires=Fri, 15 Jan 2021 11:13:21 GMT; secure; httponly
Set-Cookie: auth.sig=nl1rsPof1lOURBJ1F81MyhGsoxs; path=/; expires=Thu, 23 Jan 2020 11:13:21 GMT; secure; httponly
Set-Cookie: QINGCLOUDELB=8015b18e7b6ee1bafcfd11812d999975a4db71eff5b47ab5974a1647066247c5|XiBFV|XiBFO; path=/; HttpOnly
Set-Cookie: auth=eyJ0b2tlbiI6ImV5SmhZMk5sYzNOZmRHOXJaVzRpT2lKdVNYTkJVVzlOWldwMWNuSkJjamQ2SWl3aWNtVm1jbVZ6YUY5MGIydGxiaUk2SWpNMWNYZzVhME52V21wMFNuUXdVbTRpTENKMGIydGxibDkwZVhCbElqb2liV0ZqSWl3aVpYaHdhWEpsWDJsdUlqb3lOVGt5TURBd2ZRPT0iLCJjbGllbnRJZCI6MTU3OTE3MTcxNTI0OCwidXNlcklkIjoiNWI0MzcxNzNlNTFkNDUxOTFkNzljMjdhIn0=; path=/; expires=Thu, 23 Jan 2020 11:13:21 GMT; secure; httponly
複製代碼

能夠看到它發送了4個Cookie給我,這個4個Cookie分別爲ab=XX、_auth.sig=XX、_QINGCLOUDELB=XX、auth=XX,後面的一些path=XX、expires=XX、secure、httponly都是Cookie的附加信息,待會解釋。

我隨便點開幾篇文章,它的請求報文裏的Cookie首部都會攜帶上面的Cookie,以下:

GET /user/5b437173e51d45191d79c27a/posts HTTP/1.1
//...省略不少首部
Cookie: ab={};auth=eyJ0b2tlbiI6ImV5SmhZMk5sYzNOZmRHOXJaVzRpT2lKdVNYTkJVVzlOWldwMWNuSkJjamQ2SWl3aWNtVm1jbVZ6YUY5MGIydGxiaUk2SWpNMWNYZzVhME52V21wMFNuUXdVbTRpTENKMGIydGxibDkwZVhCbElqb2liV0ZqSWl3aVpYaHdhWEpsWDJsdUlqb3lOVGt5TURBd2ZRPT0iLCJjbGllbnRJZCI6MTU3OTE3MTcxNTI0OCwidXNlcklkIjoiNWI0MzcxNzNlNTFkNDUxOTFkNzljMjdhIn0=; auth.sig=nl1rsPof1lOURBJ1F81MyhGsoxs;QINGCLOUDELB=7526744c262201bf8ae89c7035a8ce8c9eb2c663a78c233d245e9356cc89386b|XiBG2|XiBG2;//省略了一些其餘Cookie值
複製代碼

能夠看到Cookie首部都攜帶上了ab=XX、_auth.sig=XX、_QINGCLOUDELB=XX、auth=XX這4個Cookie。

挑一個Set-Cookie值解釋一下它裏面每一個屬性的含義,以下:

Set-Cookie: ab={}; path=/; expires=Fri, 15 Jan 2021 11:13:21 GMT; secure; httponly
複製代碼

能夠看到服務器端返回的Set-Cookie首部值中,每一個屬性用分號 ; 分隔,這些屬性的解釋以下:

屬性 解釋
NAME=VALUE 表示Cookie的名稱和值,上面已經說過了,它是name=value形式的,在這裏Cookie爲ab={},ab就是名稱,{}就是值,每個Set-Cookie首部都必需含有這個,在客戶端發送請求時,Cookie會放在Cookie首部
path=路徑 Path屬性指定了服務端下的哪些路徑能夠接受Cookie值,以斜槓**/** 做爲路徑分隔符,子路徑也會被匹配,在這裏path=/,表示根目錄包括根目錄下的全部子路徑均可以接受這個Cookie值
domain=域名 雖然上面舉的例子裏沒有domain屬性,可是domain屬性經常和path屬性一塊兒指定Cookie的做用域, domain屬性指定了哪些域名的服務端能夠接受Cookie,若是指定了domain屬性,子域名也會包含,例如設置 domain=.example.com,則 子域名www2.example.com也可使用這個Cookie,若是不指定,默認爲當前服務端,但不包含子域名
expires=過時時間 expires屬性表示Cookie的有效期,在服務端發送Cookie給客戶端時,能夠設定Cookie的過時時間,當省略expires屬性時,Cookie的有效期僅維持到瀏覽器關閉以前,攜帶過時的Cookie給服務端是無效的,服務端發送過來的新的Cookie能夠覆蓋過時的Cookie
secure 含有secure屬性表示僅在進行HTTPS鏈接時,才容許發送這個Cookie
httponly 含有httponly屬性表示這個Cookie不能被JavaScript腳本調用,由於跨站腳本攻擊 (XSS) 經常使用 JavaScript 的 document.cookie api竊取用戶的 Cookie 信息,而Cookie附加了httponly屬性後,document.cookie這個api就沒法訪問Cookie信息,從而避免了XSS,可是在Web頁面內仍是能夠對Cookie進行讀取操做

跨站腳本攻擊 (XSS): 是指攻擊者誘用戶進入圈套,由用戶在不知情的狀況下執行攻擊代碼,攻擊者事先編寫腳本植入到用戶的瀏覽器頁面,用戶在運行這些頁面時就會觸發腳本,發起攻擊,常見的攻擊有:利用腳本竊取用戶的Cookie值、利用虛假輸入表單騙取用戶我的信息、顯示僞造的圖片或文章等。

7、HTTPS是什麼

一、HTTP的問題

講到HTTP不得不講HTTPS,HTTPS並不是一種新的協議,HTTPS就是安全版的HTTP,因爲HTTP設計簡單,使用簡單,致使了它存在了大量安全問題,主要體如今如下三個方面:

  • 一、HTTP通訊雙方使用不加密的明文,內容可能會被竊聽:HTTP是使用明文在網絡上進行報文的傳輸,而在網絡上進行傳輸的任何內容,都有可能被截獲,例如經過一些Wireshark、Fiddler等抓包工具就能夠抓取HTTP的報文,從而查看報文中的內容,而報文中的內容是未通過加密的明文,那麼一些重要的信息就被別人竊取到了;
  • 二、HTTP沒法驗證報文的完整性,因此報文有可能遭到篡改:沒法驗證報文的完整性是指通訊方收到這個報文時,沒法證實這個報文沒有通過中間人的篡改,沒法判斷報文中的信息是否正確,由於HTTP在發出請求到接收響應的這段時間內,有可能被其餘中間人攔截報文,中間人攔截後可能會把報文中的信息作了一些惡意的修改後才發送給通訊雙方,這樣通訊方收到報文後,就沒法得知報文內容的正確性,雖然HTTP有消息摘要校驗方法,可是不可靠;
  • 三、HTTP通訊不驗證通訊方的身份,所以有可能遇到假裝的通訊方:HTTP是基於請求/響應的方式工做,只要客戶端發出請求,服務端就要返回響應,在這個過程HTTP不會驗證通訊雙方的身份,因此頗有可能客戶端會遇到假裝的服務端,服務端會遇到假裝的客戶端,這樣就會把一些重要的信息發送給假裝者。

因此,爲了解決以上3個安全問題,就出現了HTTPS。

二、HTTPS的解決辦法

HTTPS使用加密 + 完整性保護 + 認證的方法解決上述3個問題,經過在HTTP的應用層與運輸層之間加了一層SSL/TLS,以下:

HTTP協議運行在TCP之上,HTTPS協議運行在SSL/TLS之上,SSL/TLS協議運行在TCP之上,使用HTTPS,全部傳輸的內容都要經過SSL/TLS層,加密 + 完整性保護 + 認證的工做就在SSL/TLS層中進行,換句話說HTTPS = HTTP + SSL/TLS

SSL(Secure Socket Layer)與TLS(Transport Layer Security)都是安全性協議,TLS是以SSL爲原型開發的協議,因此TLS是基於SSL,有時會把SSL和TLS統稱爲TLS,目前的主流使用是TLS1.二、TLS1.3。

下面簡單講解一下加密、完整性保護、認證的實現方式:

2.一、採用混合加密機制進行加密

爲了防止報文內容被竊聽,HTTPS採用了對稱加密 + 非對稱加密的混合加密機制。

  • 對稱加密:算法是公開的,在對稱加密算法中,加密和解密都是使用的同一個密鑰,所以對稱加密算法要保證安全性的話,密鑰要作好保密,只能讓使用的人知道,不能對外公開;

  • 非對稱加密:算法是公開的,在非對稱加密算法中,加密使用的密鑰和解密使用的密鑰是不相同的,用來加密的密鑰叫作公鑰,用來解密的密鑰叫作私鑰,公鑰是公開的,全部人均可以得到,私鑰就須要作好保密,只能讓使用的人知道,不能對外公開,非對稱密鑰除了用來加密,還能夠用來進行簽名,由於私鑰沒法被其餘人獲取,所以通訊發送方使用其私鑰進行簽名(加密),通訊接收方使用發送方的公鑰對簽名進行解密,就能判斷這個簽名是否正確.

HTTPS在通訊的時候使用對稱加密,可是使用對稱加密就有一個問題,如何把密鑰安全的發送給對方?若是簡單的經過HTTP把密鑰發送給對方,就有可能被中間人截獲,這樣對稱加密就沒有意義了,因此HTTPS採用了非對稱加密來發送對稱加密的密鑰,這個過程以下:

一、首先服務端經過非對稱加密算法生成一對密鑰:公鑰和私鑰;

二、服務端把公鑰發送給客戶端,私鑰本身保存;

三、客戶端收到公鑰後,利用公鑰對對稱加密使用的密鑰S進行加密獲得T,而後再發送給服務端;

四、服務端收到T後,利用私鑰解密T,獲得密鑰S;

五、這樣客戶端和服務端都擁有了對稱加密使用的密鑰S,在以後的通訊過程當中就使用對稱加密進行。

在這個過程當中,就算中間人獲得了T和公鑰,想要經過公鑰把T破解獲得密鑰S是很是困難的,以目前的技術來講,是幾乎不可能實現,因此這樣比直接發送密鑰安全了不少。

綜上所述,混合加密使得通訊過程的安全獲得保證,上述是爲了講解方便,在實際中,對稱密鑰不會只在客戶端生成的,它同時會在服務端生成,這在後面的HTTPS的通訊過程當中講到。

既然非對稱加密破解困難,安全,爲何通訊時不一直使用? 首先非對稱加密的運算比對稱加密的運算複雜不少,運算速度慢,因此不可能一直使用非對稱加密來通訊,而對稱加密的運算速度比非對稱加密快,效率高,因此,HTTPS就充分利用二者的優缺點,結合使用,在交換密鑰時使用非對稱加密保證安全,在通訊時使用對稱加密保證安全和效率。

2.二、採用數字簽名進行進行完整性保護

在講解數字簽名校驗以前,先來說一下HTTP的消息摘要校驗,又稱散列值校驗。

  • 消息摘要(Message Digest):原文經過MD五、SHA-1等散列值生成算法計算出的散列值就稱爲消息摘要,不管輸入的消息有多長,它的輸出長度老是固定的,而且輸出值是隨機的,消息摘要生成函數是單向函數,即沒法經過消息摘要恢復到原文,消息摘要普遍應用於數字簽名中。

HTTP的消息摘要校驗過程是這樣的:

一、服務端在發送報文以前,先用散列值生成算法生成報文的消息摘要,而後把報文和消息摘要一併發送給客戶端;

二、客戶端接收到報文和消息摘要後,就用相同散列值生成算法(已經協商過了)從新計算報文的消息摘要,若是從新計算的消息摘與發送來的消息摘要相同,就說明報文在中途沒有被篡改過,不然被篡改過;

爲何HTTP的消息摘要校驗是不可靠的?假設中間人攔截了上述過程的報文,首先經過窮舉法找出你所用的散列值生成算法,修改報文後,用散列值生成算法從新計算報文的消息摘要,而後替換掉本來的消息摘要,而後把修改後的報文和從新計算的消息摘要一併發給客戶端,客戶端按照上述相同的驗證流程,會得出報文沒有被篡改過的結論,但其實報文已經被被篡改過了,因此HTTP的消息摘要校驗是不可靠的,HTTP的消息摘要校驗不可靠主要在於中間人能夠從新生成篡改後報文的消息摘要。

因此爲了解決HTTP消息摘要校驗的缺點,HTTPS採用了數字簽名進行完整性保護,其中籤名使用到了非對稱加密的公鑰和私鑰。

  • 數字簽名(Digital Signature):用私鑰對原文進行加密後生成的密文稱爲數字簽名,數字簽名能夠經過公鑰進行驗證,把數字簽名經過公鑰解密後,若是和原文相同,就說明原文是完整的,沒有被篡改過。

因此採用了數字簽名後,校驗過程是這樣的:

一、服務端在發送報文以前,先用散列值生成算法生成報文的消息摘要,而後再用私鑰加密消息摘要生成數字簽名,把數字簽名與報文一塊兒發送給客戶端;

二、客戶端接收到報文和數字簽名後,先用相同的散列值生成算法從新計算報文的消息摘要,而後再用公鑰解密數字簽名獲得報文的消息摘要,而後比較兩份消息摘要是否相同,若是相同,說明報文在中途沒有被篡改過,不然被篡改過;

HTTPS的數字簽名是如何保證可靠性的?假設中間人截獲了報文,把報文修改後從新生成消息摘要,可是中間人沒有私鑰對生成的消息摘要進行簽名,由於私鑰是保密的,這樣他就沒法從新生成新的數字簽名,因爲中間人沒有辦法生成修改後報文的數字簽名,因此這就保證數字簽名的可靠性,接收方收到數字簽名和報文後,經過數字簽名的校驗流程,就能判斷出報文的正確性。

綜上所述,數字簽名使得消息的完整性獲得保證,在HTTPS中,數字簽名通常會用到數字證書的傳遞上,下面會講。

爲何HTTPS要生成報文的消息摘後,再對消息摘要進行簽名,而不對報文直接簽名? 這是由於報文內容通常都很長,而報文的消息摘要輸出的長度是固定,比報文長度短,這樣經過私鑰進行加密的運算量就大大減小,提升效率,因此當非對稱加密與消息摘要結合使用後,便造成了一種高效又安全的數字簽名方案。

2.三、採用數字證書進行身份認證

你們有沒有發現,前面所講的數字簽名和混合加密技術,客戶端都必須事先知道服務端的公鑰,若是一開始公鑰就被中間人篡改了,那麼壞人就會被你當成好人,你就會拿着這把假的公鑰和假的服務端通訊,因此如何保證公鑰是真正的服務端頒發,又是另一個問題,爲了保證公鑰的安全可信,HTTPS經過數字證書來解決服務端的身份認證問題。

  • 數字證書(Digital Certificate):數字證書是由數字認證機構(Certificate Authority, 簡稱CA)頒發的公開密鑰證書,它裏面大概包含以下信息:

    一、發佈機構(Issuer): 表示該證書是由哪一個機構(CA)頒發的;

    二、有效期(Validity): 表示證書的使用期限,過了有效期,證書就失效了

    三、名稱(Subject):表示證書全部人的名字,這個證書是發給誰的,通常是某我的或者某個公司名稱、機構的名稱、公司網站的網址等;

    四、公鑰(Public-Key): 表示證書全部人想要公佈出去的公鑰;

    五、簽名算法(Signature algorithm): 表示證書的數字簽名所使用的加密算法,這樣就可使用證書發佈機構的證書裏面的公鑰,根據這個算法對數字簽名進行解密;

    六、數字簽名(Digital Signature):表示證書發行者CA對該證書的數字簽名,用於保證數字證書的完整性,確保證書沒有被修改過.

數字認證機構是處於客戶端和服務端雙方都信賴的第三方機構,由CA頒發的數字證書必定是可靠、可信的,下面來簡單介紹一下服務端向CA申請數字證書的流程:

一、服務端的運營人員向CA提交本身的公鑰、組織信息、域名等信息,而後CA會經過各類渠道、各類手段來判斷服務端的身份是否真實,是否合法等(在這裏就能夠杜絕中間人非法申請證書);

二、服務端的身份審覈經過後,CA就會把服務端的公鑰和證書的其餘信息經過散列值算法生成一個消息摘要,而後用CA的私鑰對消息摘要進行簽名生成數字簽名,而後把數字簽名放入證書中,而後把這個證書頒發給服務端,因此數字證書最終包含服務端公鑰 + 證書的數字簽名 + 證書的其餘信息,以下:

如今服務端拿到了數字證書,客戶端第一次請求服務端時,服務端就會把這個數字證書發送給客戶端,客戶端收到數字證書後,就會用CA的公鑰對數字證書進行數字簽名的驗證,若是驗證經過,說明數字證書中途沒有被篡改過,是可靠的,從而知道數字證書中的公鑰也是可靠的,因此客戶端就放心的取出數字證書中的公鑰進行之後的HTTPS通訊。

在對數字證書的數字簽名進行驗證以前,必須先知道CA的公鑰,由於數字證書的數字簽名是由CA的私鑰進行簽名的,因此CA的公鑰必須安全的轉交給客戶端,如何安全的轉交又是一個困難的問題,因此,大多數瀏覽器開發商發佈版本時,會事先在內部植入經常使用的CA機構的根證書, 這些根證書中會包含CA的公鑰,也就是說CA的公鑰已經內置在瀏覽器中了。

綜上所述,數字證書能夠確認服務端的身份,能夠解決公鑰的安全發放問題,同時數字證書也是經過數字簽名來驗證的。

瀏覽器內置的CA都是經常使用的、信任的CA機構,因此若是服務端發來的數字證書的相關CA機構恰好不在瀏覽器的內置CA列表中,瀏覽器就會找不到該數字證書的CA公鑰,就會斷定該數字證書是非法,這時瀏覽器會提示你手動安裝該數字證書的CA機構的根證書,這個時候你就要本身承擔風險了,頗有可能這個網站是不可信任的,安裝了根證書後就能夠拿到CA的公鑰進行數字證書的驗證,驗證經過後就能與服務端通訊。

打開一個由HTTPS鏈接 (地址欄上有一個鎖的標誌) 的網站,經過如下方式查看它的數字證書,以下:

三、HTTPS的通訊過程

在進行HTTPS通訊前,必須先進行TCP三次握手創建TCP鏈接,而後進行TLS握手,進行完TLS握手後纔會開始加密的HTTPS通訊,在TLS握手的過程當中主要進行密鑰交換(對稱加密使用的密鑰)、身份認證等步驟,根據密鑰交換時使用的算法不一樣,TLS握手能夠分爲RSA握手和DH握手,目前主流的是DH握手,並且RSA握手因爲它沒有向前保密,已經在TLS1.3中被淘汰了,關於這兩個握手算法的主要細節與區別能夠查看下面文章,限於篇幅,本文不展開討論:

Keyless SSL: The Nitty Gritty Technical Details

HTTPS篇之SSL握手過程詳解

我經過抓取各大主流網站的TLS包發現,目前HTTPS使用的TLS版本幾乎都是TLS1.2TLS1.3版本,下面的分析都是基於TLS1.2的DH握手過程,下面是我打開第一次打開csdn博客時抓取的TLS包(通過過濾後),以下:

其中info欄的信息表示TLS握手過程當中客戶端和服務端之間交互時發送的TLS包的名稱,有Server Key Exchange包表示它本次的握手類型是DH握手,上面的TLS握手過程能夠用下圖表示,以下:

上圖省略了New Session Ticket包,New Session Ticket包是用於會話複用,並非必要的,省略它並不會影響對TLS握手過程的理解,在TLS握手完成以前,報文的傳輸都是明文,TLS握手過程的每一個步驟的解釋以下:

  • 步驟1:客戶端發送Client Hello報文給服務端,表示開始TLS握手,Client Hello報文中包含客戶端支持的TLS版本(Version)、支持的加密組件列表(Cipher Suites)、客戶端生成的隨機數(Random)等信息;
  • 步驟2:服務端收到Client Hello報文後,若是能夠開始進行通訊,就會發送Server Hello報文給客戶端做爲迴應,Server Hello報文中包含支持的TLS版本(Version)、從加密組件列表中選擇的加密組件(Cipher Suite)、服務端生成的隨機數(Random)等信息,其中加密組件用於告訴客戶端接下來身份認證、密鑰交換、對稱加密等過程使用的算法;
  • 步驟3:緊接着服務端就會發送Certificate報文,報文中包含服務端的數字證書,即公鑰證書,客戶端收到證書後,就會對服務端進行身份認證,身份認證使用的算法就是在步驟2協商好的認證算法,通常會使用RSA;
  • 步驟4:接着服務端就會發送Server Key Exchange報文,Server Key Exchange報文中包含服務端根據相應的DH算法生成DH參數(PubKey),這個DH算法就是在步驟2協商好的密鑰交換算法;
  • 步驟5: 最後服務端發送Server Hello Done報文通知客戶端它完成了TLS握手的一半,服務端到目前爲止向客戶端發送了服務端的隨機數、證書、服務端的DH參數;
  • 步驟6:接下來客戶端向服務端發送Client Key Exchange報文,Client Key Exchange報文中包含客戶端根據相應的DH算法生成的DH參數(PubKey),這個DH算法一樣是在步驟2協商好的密鑰交換算法;
  • 步驟7:緊接着客戶端就會使用在步驟1本身生成的隨機數、在步驟2收到的服務端隨機數、在步驟4收到的服務端DH參數、在步驟6本身生成的DH參數這四個參數,經過在步驟2協商好的對稱加密算法來生成之後通訊過程當中使用的密鑰,這裏記爲S,而後客戶端就會發送Change Cipher Spec報文通知服務端對稱加密使用的密鑰生成完畢,接下來客戶端向服務端發送的數據都會通過密鑰加密;
  • 步驟8:最後客戶端發送Encrypted Handshake Message報文通知服務端它完成了TLS握手的全部內容,Encrypted Handshake Message報文包含至今全部報文的總體校驗值,並用*S加密,本次握手可否成功,取決於服務端可否解密這個報文,Encrypted Handshake Message報文下面的兩個Application Data報文就是客戶端通過加密後發給服務端的數據,客戶端到目前爲止向服務端發送了客戶端的隨機數、客戶端的DH參數;
  • 步驟9:緊接着服務端就會使用在步驟2本身生成的隨機數、在步驟1收到的客戶端隨機數、在步驟6收到的客戶端DH參數、在步驟4本身生成的DH參數這四個參數,經過在步驟2協商好的對稱加密算法來生成之後通訊過程當中使用的密鑰,這裏記爲T,因爲DH算法的保證:T == S,這樣客戶端和服務端都擁有了通訊加密使用的密鑰,而後服務端就會發送Change Cipher Spec報文通知客戶端對稱加密使用的密鑰生成完畢,接下來服務端向客戶端發送的數據都會通過密鑰加密;
  • 步驟10:最後服務端發送Encrypted Handshake Message報文通知客戶端它完成了TLS握手的全部內容,Encrypted Handshake Message報文包含至今全部報文的總體校驗值,並用*T加密,本次握手可否成功,取決於客戶端可否解密這個報文。

若是客戶端和服務端都成功解密了最後那個Encrypted Handshake Message報文,證實客戶端和服務端的對稱密鑰生成完畢,TLS握手都所有完成,接下來雙方均可以經過對稱密鑰進行加密通訊,Application Data報文中的數據就是加密後的HTTP報文,當HTTPS通訊結束後,由客戶端主動發出Client Close Notify報文斷開鏈接。

由上面DH握手過程能夠看出,對稱密鑰是根據一些參數在各端生成,並非在客戶端生成後經過公鑰加密傳輸給服務端,這樣作是爲了保證服務端的私鑰不和對稱密鑰有關聯,什麼意思呢?若是在客戶端生成密鑰經過公鑰加密傳輸給服務端,服務端能夠由私鑰解密出密鑰,這樣私鑰就參與了對稱密鑰的解密,到也就是說,只要我擁有服務端的私鑰,我就能夠解密出密鑰,因此若是中間人把你TLS握手過程當中的全部報文攔截、保存,直到某一天服務端的私鑰泄漏了,中間人就可使用私鑰在保存的報文中解密出密鑰,這樣,中間人就輕鬆的解密出客戶端和服務端之後的通訊內容,而經過DH參數的交換就能夠避免這個漏洞,爲何DH交換就能夠? 這歸根究竟是一個數學問題,你們能夠自行查找資料。

你們只須要知道在TLS握手中,對稱密鑰是服務端和客戶端各自生成的,服務端公鑰和私鑰的功能被削弱到用來進行身份認證或者簽名驗證,這麼作的目的都是爲了保證通訊的向前保密、安全。

HTTPS這麼安全,爲何不全部網站都使用? 一、效率問題:與HTTP的明文通訊相比,加密通訊須要消耗更多的CPU資源與內存; 二、部署問題:使用HTTPS須要有權威CA的證書頒發,從證書的選擇、購買到部署都是一個耗時耗力的過程; 三、成本問題:購買證書也是一筆開銷.

結語

網絡請求已經成爲了一個應用最基本的部分,因此熟悉HTTP對於咱們開發很重要,咱們不只會用開發環境提供給咱們的API,還要屬性它的原理,本文從發展歷史、工做特色、報文格式、狀態碼、常見首部、HTTPS這幾個方面總結了一番HTTP,固然,HTTP確定不止這一些,一篇文章是沒法講完的,限於篇幅,還有HTTP的緩存機制沒有講,這也是很重要的內容,掌握以上這些足夠日常使用了。

以上就是本文所有內容,但願你們有所收穫。

參考資料:

圖解HTTP

HTTP1.0、HTTP1.1 和 HTTP2.0 的區別

深度解密 HTTP 通訊細節

HTTP/1.x 的鏈接管理

深刻理解https工做原理

SSL中的RSA、DHE、ECDHE、ECDH流程與區別

Cookie/Session的機制與安全

相關文章
相關標籤/搜索