一 、基礎概念

URI

URI 包含 URL 和 URN。

請求和響應報文

1. 請求報文

2. 響應報文

二、HTTP 方法

客戶端發送的 請求報文 第一行為請求行,包含了方法欄位。

GET

獲取資源

當前網路請求中,絕大部分使用的是 GET 方法。

HEAD

獲取報文首部

和 GET 方法類似,但是不返回報文實體主體部分。

主要用於確認 URL 的有效性以及資源更新的日期時間等。

POST

傳輸實體主體

POST 主要用來傳輸數據,而 GET 主要用來獲取資源。

更多 POST 與 GET 的比較請見第九章。

PUT

上傳文件

由於自身不帶驗證機制,任何人都可以上傳文件,因此存在安全性問題,一般不使用該方法。

PUT /new.html HTTP/1.1
Host: example.com
Content-type: text/html
Content-length: 16

<p>New File</p>

PATCH

對資源進行部分修改

PUT 也可以用於修改資源,但是隻能完全替代原始資源,PATCH 允許部分修改。

PATCH /file.txt HTTP/1.1
Host: www.example.com
Content-Type: application/example
If-Match: "e0023aa4e"
Content-Length: 100

[description of changes]

DELETE

刪除文件

與 PUT 功能相反,並且同樣不帶驗證機制。

DELETE /file.html HTTP/1.1

OPTIONS

查詢支持的方法

查詢指定的 URL 能夠支持的方法。

會返回 Allow: GET, POST, HEAD, OPTIONS 這樣的內容。

CONNECT

要求在與代理伺服器通信時建立隧道

使用 SSL(Secure Sockets Layer,安全套接層)和 TLS(Transport Layer Security,傳輸層安全)協議把通信內容加密後經網路隧道傳輸。

CONNECT www.example.com:443 HTTP/1.1

TRACE

追蹤路徑

伺服器會將通信路徑返回給客戶端。

發送請求時,在 Max-Forwards 首部欄位中填入數值,每經過一個伺服器就會減 1,當數值為 0 時就停止傳輸。

通常不會使用 TRACE,並且它容易受到 XST 攻擊(Cross-Site Tracing,跨站追蹤)。

三、HTTP 狀態碼

伺服器返回的 響應報文 中第一行為狀態行,包含了狀態碼以及原因短語,用來告知客戶端請求的結果。

狀態碼類別含義1XXInformational(信息性狀態碼)接收的請求正在處理2XXSuccess(成功狀態碼)請求正常處理完畢3XXRedirection(重定向狀態碼)需要進行附加操作以完成請求4XXClient Error(客戶端錯誤狀態碼)伺服器無法處理請求5XXServer Error(伺服器錯誤狀態碼)伺服器處理請求出錯

1XX 信息

  • 100 Continue :表明到目前為止都很正常,客戶端可以繼續發送請求或者忽略這個響應。

2XX 成功

  • 200 OK
  • 204 No Content :請求已經成功處理,但是返回的響應報文不包含實體的主體部分。一般在只需要從客戶端往伺服器發送信息,而不需要返回數據時使用。
  • 206 Partial Content :表示客戶端進行了範圍請求,響應報文包含由 Content-Range 指定範圍的實體內容。

3XX 重定向

  • 301 Moved Permanently :永久性重定向
  • 302 Found :臨時性重定向
  • 303 See Other :和 302 有著相同的功能,但是 303 明確要求客戶端應該採用 GET 方法獲取資源。
  • 註:雖然 HTTP 協議規定 301、302 狀態下重定向時不允許把 POST 方法改成 GET 方法,但是大多數瀏覽器都會在 301、302 和 303 狀態下的重定向把 POST 方法改成 GET 方法。
  • 304 Not Modified :如果請求報文首部包含一些條件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不滿足條件,則伺服器會返回 304 狀態碼。
  • 307 Temporary Redirect :臨時重定向,與 302 的含義類似,但是 307 要求瀏覽器不會把重定向請求的 POST 方法改成 GET 方法。

4XX 客戶端錯誤

  • 400 Bad Request :請求報文中存在語法錯誤。
  • 401 Unauthorized :該狀態碼錶示發送的請求需要有認證信息(BASIC 認證、DIGEST 認證)。如果之前已進行過一次請求,則表示用戶認證失敗。
  • 403 Forbidden :請求被拒絕。
  • 404 Not Found

5XX 伺服器錯誤

  • 500 Internal Server Error :伺服器正在執行請求時發生錯誤。
  • 503 Service Unavailable :伺服器暫時處於超負載或正在進行停機維護,現在無法處理請求。

四、HTTP 首部

有 4 種類型的首部欄位:通用首部欄位、請求首部欄位、響應首部欄位和實體首部欄位。

各種首部欄位及其含義如下(不需要全記,僅供查閱):

通用首部欄位

首部欄位名說明Cache-Control控制緩存的行為Connection控制不再轉發給代理的首部欄位、管理持久連接Date創建報文的日期時間Pragma報文指令Trailer報文末端的首部一覽Transfer-Encoding指定報文主體的傳輸編碼方式Upgrade升級為其他協議Via代理伺服器的相關信息Warning錯誤通知

請求首部欄位

首部欄位名說明Accept用戶代理可處理的媒體類型Accept-Charset優先的字符集Accept-Encoding優先的內容編碼Accept-Language優先的語言(自然語言)AuthorizationWeb 認證信息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-AgentHTTP 客戶端程序的信息

響應首部欄位

首部欄位名說明Accept-Ranges是否接受位元組範圍請求Age推算資源創建經過時間ETag資源的匹配信息Location令客戶端重定向至指定 URIProxy-Authenticate代理伺服器對客戶端的認證信息Retry-After對再次發起請求的時機要求ServerHTTP 伺服器的安裝信息Vary代理伺服器緩存的管理信息WWW-Authenticate伺服器對客戶端的認證信息

實體首部欄位

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

五、具體應用

連接管理

1. 短連接與長連接

當瀏覽器訪問一個包含多張圖片的 HTML 頁面時,除了請求訪問的 HTML 頁面資源,還會請求圖片資源。如果每進行一次 HTTP 通信就要新建一個 TCP 連接,那麼開銷會很大。

長連接只需要建立一次 TCP 連接就能進行多次 HTTP 通信。

  • 從 HTTP/1.1 開始默認是長連接的,如果要斷開連接,需要由客戶端或者伺服器端提出斷開,使用 Connection : close
  • 在 HTTP/1.1 之前默認是短連接的,如果需要使用長連接,則使用 Connection : Keep-Alive

2. 流水線

默認情況下,HTTP 請求是按順序發出的,下一個請求只有在當前請求收到響應之後才會被發出。由於受到網路延遲和帶寬的限制,在下一個請求被發送到伺服器之前,可能需要等待很長時間。

流水線是在同一條長連接上連續發出請求,而不用等待響應返回,這樣可以減少延遲。

Cookie

HTTP 協議是無狀態的,主要是為了讓 HTTP 協議儘可能簡單,使得它能夠處理大量事務。HTTP/1.1 引入 Cookie 來保存狀態信息。

Cookie 是伺服器發送到用戶瀏覽器並保存在本地的一小塊數據,它會在瀏覽器之後向同一伺服器再次發起請求時被攜帶上,用於告知服務端兩個請求是否來自同一瀏覽器。由於之後每次請求都會需要攜帶 Cookie 數據,因此會帶來額外的性能開銷(尤其是在移動環境下)。

Cookie 曾一度用於客戶端數據的存儲,因為當時並沒有其它合適的存儲辦法而作為唯一的存儲手段,但現在隨著現代瀏覽器開始支持各種各樣的存儲方式,Cookie 漸漸被淘汰。新的瀏覽器 API 已經允許開發者直接將數據存儲到本地,如使用 Web storage API(本地存儲和會話存儲)或 IndexedDB。

1. 用途

  • 會話狀態管理(如用戶登錄狀態、購物車、遊戲分數或其它需要記錄的信息)
  • 個性化設置(如用戶自定義設置、主題等)
  • 瀏覽器行為跟蹤(如跟蹤分析用戶行為等)

2. 創建過程

伺服器發送的響應報文包含 Set-Cookie 首部欄位,客戶端得到響應報文後把 Cookie 內容保存到瀏覽器中。

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

[page content]

客戶端之後對同一個伺服器發送請求時,會從瀏覽器中取出 Cookie 信息並通過 Cookie 請求首部欄位發送給伺服器。

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

3. 分類

  • 會話期 Cookie:瀏覽器關閉之後它會被自動刪除,也就是說它僅在會話期內有效。
  • 持久性 Cookie:指定過期時間(Expires)或有效期(max-age)之後就成為了持久性的 Cookie。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

4. 作用域

Domain 標識指定了哪些主機可以接受 Cookie。如果不指定,默認為當前文檔的主機(不包含子域名)。如果指定了 Domain,則一般包含子域名。例如,如果設置 Domain=mozilla.org,則 Cookie 也包含在子域名中(如 developer.mozilla.org)。

Path 標識指定了主機下的哪些路徑可以接受 Cookie(該 URL 路徑必須存在於請求 URL 中)。以字元 %x2F ("/") 作為路徑分隔符,子路徑也會被匹配。例如,設置 Path=/docs,則以下地址都會匹配:

  • /docs
  • /docs/Web/
  • /docs/Web/HTTP

5. JavaScript

瀏覽器通過 document.cookie 屬性可創建新的 Cookie,也可通過該屬性訪問非 HttpOnly 標記的 Cookie。

document.cookie = "yummy_cookie=choco";
document.cookie = "tasty_cookie=strawberry";
console.log(document.cookie);

6. HttpOnly

標記為 HttpOnly 的 Cookie 不能被 JavaScript 腳本調用。跨站腳本攻擊 (XSS) 常常使用 JavaScript 的 document.cookie API 竊取用戶的 Cookie 信息,因此使用 HttpOnly 標記可以在一定程度上避免 XSS 攻擊。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

7. Secure

標記為 Secure 的 Cookie 只能通過被 HTTPS 協議加密過的請求發送給服務端。但即便設置了 Secure 標記,敏感信息也不應該通過 Cookie 傳輸,因為 Cookie 有其固有的不安全性,Secure 標記也無法提供確實的安全保障。

8. Session

除了可以將用戶信息通過 Cookie 存儲在用戶瀏覽器中,也可以利用 Session 存儲在伺服器端,存儲在伺服器端的信息更加安全。

Session 可以存儲在伺服器上的文件、資料庫或者內存中。也可以將 Session 存儲在 Redis 這種內存型資料庫中,效率會更高。

使用 Session 維護用戶登錄狀態的過程如下:

  • 用戶進行登錄時,用戶提交包含用戶名和密碼的表單,放入 HTTP 請求報文中;
  • 伺服器驗證該用戶名和密碼,如果正確則把用戶信息存儲到 Redis 中,它在 Redis 中的 Key 稱為 Session ID;
  • 伺服器返回的響應報文的 Set-Cookie 首部欄位包含了這個 Session ID,客戶端收到響應報文之後將該 Cookie 值存入瀏覽器中;
  • 客戶端之後對同一個伺服器進行請求時會包含該 Cookie 值,伺服器收到之後提取出 Session ID,從 Redis 中取出用戶信息,繼續之前的業務操作。

應該注意 Session ID 的安全性問題,不能讓它被惡意攻擊者輕易獲取,那麼就不能產生一個容易被猜到的 Session ID 值。此外,還需要經常重新生成 Session ID。在對安全性要求極高的場景下,例如轉賬等操作,除了使用 Session 管理用戶狀態之外,還需要對用戶進行重新驗證,比如重新輸入密碼,或者使用簡訊驗證碼等方式。

9. 瀏覽器禁用 Cookie

此時無法使用 Cookie 來保存用戶信息,只能使用 Session。除此之外,不能再將 Session ID 存放到 Cookie 中,而是使用 URL 重寫技術,將 Session ID 作為 URL 的參數進行傳遞。

10. Cookie 與 Session 選擇

  • Cookie 只能存儲 ASCII 碼字元串,而 Session 則可以存儲任何類型的數據,因此在考慮數據複雜性時首選 Session;
  • Cookie 存儲在瀏覽器中,容易被惡意查看。如果非要將一些隱私數據存在 Cookie 中,可以將 Cookie 值進行加密,然後在伺服器進行解密;
  • 對於大型網站,如果用戶所有的信息都存儲在 Session 中,那麼開銷是非常大的,因此不建議將所有的用戶信息都存儲到 Session 中。

六、HTTPS

HTTP 有以下安全性問題:

  • 使用明文進行通信,內容可能會被竊聽;
  • 不驗證通信方的身份,通信方的身份有可能遭遇偽裝;
  • 無法證明報文的完整性,報文有可能遭篡改。

HTTPS 並不是新協議,而是讓 HTTP 先和 SSL(Secure Sockets Layer)通信,再由 SSL 和 TCP 通信,也就是說 HTTPS 使用了隧道進行通信。

通過使用 SSL,HTTPS 具有了加密(防竊聽)、認證(防偽裝)和完整性保護(防篡改)。

加密

1. 對稱密鑰加密

對稱密鑰加密(Symmetric-Key Encryption),加密和解密使用同一密鑰。

  • 優點:運算速度快;
  • 缺點:無法安全地將密鑰傳輸給通信方。

2.非對稱密鑰加密

非對稱密鑰加密,又稱公開密鑰加密(Public-Key Encryption),加密和解密使用不同的密鑰。

公開密鑰所有人都可以獲得,通信發送方獲得接收方的公開密鑰之後,就可以使用公開密鑰進行加密,接收方收到通信內容後使用私有密鑰解密。

非對稱密鑰除了用來加密,還可以用來進行簽名。因為私有密鑰無法被其他人獲取,因此通信發送方使用其私有密鑰進行簽名,通信接收方使用發送方的公開密鑰對簽名進行解密,就能判斷這個簽名是否正確。

  • 優點:可以更安全地將公開密鑰傳輸給通信發送方;
  • 缺點:運算速度慢。

3. HTTPS 採用的加密方式

HTTPS 採用混合的加密機制,使用非對稱密鑰加密用於傳輸對稱密鑰來保證傳輸過程的安全性,之後使用對稱密鑰加密進行通信來保證通信過程的效率。(下圖中的 Session Key 就是對稱密鑰)

推薦閱讀:

相關文章