JSON Web Token 入門教程

JSON Web TokenJWT)是一種可以在多方之間安全共享數據的開放標準,JWT 數據經過編碼和數字簽名生成,可以確保其真實性,也因此 JWT 通常用於身份認證。這篇文章會介紹什麼是 JWT,JWT 的應用場景以及組成結構,最後分析它的優點及侷限性。

傳統認證方式的問題

在介紹 JWT 之前,先看下傳統認證方式有什麼問題,這裏的傳統認證方式是指 Session-Cookie 方式。有小夥伴可能要說了,傳統認證方式能有什麼問題,如果有問題肯定是你代碼寫的不好。其實不是,有些問題存在於方案本身。

先來看一下傳統的認證方式流程:

    1. 客戶端輸入用戶名密碼,點擊登錄。
    1. 服務端驗證用戶名密碼,校驗通過,服務端存儲 Session 數據,如身份,權限。
    1. 服務端響應 Cookie,一般內容是一個 Session ID,客戶端收到 Cookie 後存儲。
    1. 客戶端後續請求攜帶 Cookie 作爲身份認證憑據,服務端驗證 Cookie 得知用戶身份。

這是常見的認證流程,但是這種認證方式存在下面幾個問題。

狀態存儲負擔

Session-Cookie 方式因爲服務端要存儲當前會話信息,而且必不可少, 這就額外增加了存儲負擔,而且在分佈式系統中,還要考慮不同機器之間的會話狀態同步問題。有時還需要部署獨立的認證服務。不易維護。

跨域問題

基於 Cookie 會話的認證方式,在進行跨域請求時存在難點,Cookie 不會跟隨跨域請求。認證信息帶不過去,當然,聰明的小夥伴可以通過設置客戶端參數,配置服務端參數等操作來允許跨域,不過有點麻煩了。

CSRF 攻擊風險

CSRF(Cross-Site Request Forgery,跨站請求僞造)是一種常見的 Web 安全漏洞。有些小夥伴不知道是什麼意思,看下面流程:

    1. 你登錄了 QQ 空間,傳統認證方式,客戶端成功存儲了 Cookie。
    1. 你的 “好友 X” 給你發了一個鏈接,標題 “專家:喫澱粉腸活不過三年”。
    1. 突然你感覺彷彿昨晚澱粉腸的香味還沒散去,你迫不及待的點開了,沒想到自動跳轉到了 QQ 空間,你感覺莫名其妙,大失所望,立馬關掉。
    1. 但是沒想到的是這個跳轉請求了空間說說發表接口,因爲你之前登錄過,Cookie 狀態還在。說說直接發表成功了。那馬上可能就有好友問你空間發的亂七八糟的內容是什麼意思了。

QQ 空間曾經也確實出現過 CSRF 漏洞。

在解決這幾個問題上,JWT 具有天然優勢,它存儲在客戶端,服務端無狀態。Token 可以不存在 Cookie 中,輕鬆跨域又減少了 CSRF 風險。

JWT 是什麼

JWT(JSON Web Tokens)它定義了一種緊湊自包含的方式用於在各方之間作爲 JSON 對象安全地傳遞信息。緊湊意味着內容儘可能的短小。自包含意味着內容中包含了身份信息。這個信息可以用於身份認證,也可以用於信息交換。由於信息會使用密鑰進行數字簽名,因此 JWT 可以被驗證以及信任。

JWT 應用場景

常見的 JWT 應用常見有 JWT 授權和信息交換:

JWT 組成結構

JWT 由小數點分割的三部分組成,如 xxxxx.yyyyy.zzzzz,這三部分對應的是的標頭(Header)、負載(Payload)、簽名(Signature),每部分使用 Base64Url 進行編碼,

下面是一個真實 JWT 示例:

JWT 示例

注意:JWT 爲緊湊形式,沒有換行,這裏爲了方便閱讀,進行了換行。

標頭 Header

Header 部分 Base64Url 解碼後可以看到兩個字段,alg 指定簽名算法,typ 指定 Token 類型。

{
  "alg""HS256",
  "typ""JWT"
}

對上述標頭對象進行 Base64Url 編碼以形成 JWT 的第一部分。

負載 Payload

第二部分中存放了實際需要的數據,用戶可以自定義內容,如用戶身份信息。

{
  "sub""1234567890",
  "name""John Doe",
  "iat"1516239022
}

同時 JWT 也規定了幾個官方字段:

iss (issuer):簽發人
sub (subject):主題
aud (audience):受衆
nbf (Not Before):生效時間
exp (expiration time):過期時間
iat (Issued At):簽發時間
jti (JWT ID):編號

可以看到不管第一部分還是第二部分,字段名都是三位字母,這也是爲了內容的緊湊。對 JWT 負載進行 Base64Url 編碼以形成 JWT 的第二部分。

特別注意:由於只要 Base64Url 解碼就可以看到第二部分內容,因此不能在 Payload 中存儲敏感信息。

簽名 Signature

簽名 Signature 的生成依賴標頭 Header 和負載 Payload ,同時要有擁有用於簽名的密鑰,因此簽名可以用於驗證 JWT 的發送者是否正確,並確保消息沒有被篡改。

Signature = HMACSHA256(
  base64UrlEncode(header) + '.' +
  base64UrlEncode(payload),
  secret)

JWT 官網也提供 JWT 在線解碼驗證工具 [1],可以訪問查看。

JWT 在線驗證

JWT 身份認證

使用 JWT 進行身份認證的工作流程如下:

    1. 用戶使用登錄憑證(如用戶名和密碼)進行登錄。
    1. 服務器驗證憑證的正確性,並創建一個包含用戶信息的 JWT。
    1. 服務器對 JWT 進行簽名,然後將其發送回用戶。
    1. 用戶將 JWT 存儲在客戶端(如 localStorage),並在隨後的請求中隨同發送。如添加到請求頭:Authorization: Bearer <token>
    1. 服務器在接收到請求後,驗證 JWT 的簽名並解析其內容,確認用戶的身份,然後返回請求的數據。
    1. JWT 可能在一定時間後過期,用戶需要重新登錄獲取新的 JWT。

JWT 的特點

JWT 有下面幾個特點。

  1. 1. 緊湊:JWT 設計十分緊湊,結果較小,可以在參數,請求頭中傳輸。

  2. 2. 自包含:JWT 自身包含了用戶驗證的所需信息,避免了多次查詢數據庫。

  3. 3. 跨語言:JWT 使用 JSON 格式,現代編程語言都有對 JSON 的支持。

  4. 4. 安全性:JWT 需要使用密鑰進行數據簽名,密鑰不泄露,JWT 就是安全的。但是因爲 JWT 自包含和 Base64Url 編碼特性,JWT 中的信息可以被直接讀取,因此建議使用 HTTPS 協議。如果對安全性要求較高,還可以對 JWT 內容在進行一次加密(如 AES)。

  5. 5. 分佈式環境友好:因爲 JWT 在服務端無狀態,因此 JWT 適用於單點登錄,同時可以跨域

  6. 6. 不可撤銷:一旦 JWT 簽發了,在有效期內將會一直有效,除非服務器增加額外邏輯來強制撤銷某個 JWT Token,如黑名單機制。

  7. 7. 性能問題:雖然避免了查詢數據庫,但是服務器仍需對每個請求中的 JWT 進行解碼和驗證,如果請求量巨大,這也可能成爲性能瓶頸。

JWT 最佳實踐

JWT 存在優點,也有很多風險與挑戰,參考前人的最佳實踐可以少走彎路。

    1. 內容緊湊最小化:最小限度的減少 JWT 負載中的內容,避免存儲敏感數據,只存儲重要數據。某些服務器不接受大於 8KB 的請求頭。
    1. 驗證必不可少:每次收到 JWT 都要進行驗證,內容驗證,過期時間驗證。發行者驗證。
    1. 使用 JWT 庫:不要自己編寫 JWT 類庫,密碼學和安全都是非常複雜的東西,使用專業的類庫好過自己編寫。
    1. JWT 過期時間:設計合理的過期時間,因爲 JWT 一旦頒發,無法刪除。過長的有效期存在風險。

總體而言,JWT 提供了一種相對簡單且有效的方式來處理身份驗證問題,但是需要注意 JWT 安全性和細節問題,以確保 JWT 可以在應用中正確且安全地使用。

預告:下一篇文章會介紹如何在 Java 中使用 JWT 進行身份驗證。

參考

引用鏈接

[1] JWT 在線解碼驗證工具: _https://jwt.io/?_gl=11igv4lh_gaNTkxODM4NDM2LjE3MTA1ODM3NTM.ga_QKMSDV5369*MTcxMDgwOTgyOS40LjEuMTcxMDgxMDgyNC41Ny4wLjA.

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/wIxg55riF03u25CJhJrM5g