JSON Web Token 入門教程
JSON Web Token(JWT)是一種可以在多方之間安全共享數據的開放標準,JWT 數據經過編碼和數字簽名生成,可以確保其真實性,也因此 JWT 通常用於身份認證。這篇文章會介紹什麼是 JWT,JWT 的應用場景以及組成結構,最後分析它的優點及侷限性。
傳統認證方式的問題
在介紹 JWT 之前,先看下傳統認證方式有什麼問題,這裏的傳統認證方式是指 Session-Cookie
方式。有小夥伴可能要說了,傳統認證方式能有什麼問題,如果有問題肯定是你代碼寫的不好。其實不是,有些問題存在於方案本身。
先來看一下傳統的認證方式流程:
-
- 客戶端輸入用戶名密碼,點擊登錄。
-
- 服務端驗證用戶名密碼,校驗通過,服務端存儲 Session 數據,如身份,權限。
-
- 服務端響應 Cookie,一般內容是一個 Session ID,客戶端收到 Cookie 後存儲。
-
- 客戶端後續請求攜帶 Cookie 作爲身份認證憑據,服務端驗證 Cookie 得知用戶身份。
這是常見的認證流程,但是這種認證方式存在下面幾個問題。
狀態存儲負擔
Session-Cookie
方式因爲服務端要存儲當前會話信息,而且必不可少, 這就額外增加了存儲負擔,而且在分佈式系統中,還要考慮不同機器之間的會話狀態同步問題。有時還需要部署獨立的認證服務。不易維護。
跨域問題
基於 Cookie 會話的認證方式,在進行跨域請求時存在難點,Cookie 不會跟隨跨域請求。認證信息帶不過去,當然,聰明的小夥伴可以通過設置客戶端參數,配置服務端參數等操作來允許跨域,不過有點麻煩了。
CSRF 攻擊風險
CSRF(Cross-Site Request Forgery,跨站請求僞造)是一種常見的 Web 安全漏洞。有些小夥伴不知道是什麼意思,看下面流程:
-
- 你登錄了 QQ 空間,傳統認證方式,客戶端成功存儲了 Cookie。
-
- 你的 “好友 X” 給你發了一個鏈接,標題 “專家:喫澱粉腸活不過三年”。
-
- 突然你感覺彷彿昨晚澱粉腸的香味還沒散去,你迫不及待的點開了,沒想到自動跳轉到了 QQ 空間,你感覺莫名其妙,大失所望,立馬關掉。
-
- 但是沒想到的是這個跳轉請求了空間說說發表接口,因爲你之前登錄過,Cookie 狀態還在。說說直接發表成功了。那馬上可能就有好友問你空間發的亂七八糟的內容是什麼意思了。
QQ 空間曾經也確實出現過 CSRF 漏洞。
在解決這幾個問題上,JWT 具有天然優勢,它存儲在客戶端,服務端無狀態。Token 可以不存在 Cookie 中,輕鬆跨域又減少了 CSRF 風險。
JWT 是什麼
JWT(JSON Web Tokens)它定義了一種緊湊且自包含的方式用於在各方之間作爲 JSON 對象安全地傳遞信息。緊湊意味着內容儘可能的短小。自包含意味着內容中包含了身份信息。這個信息可以用於身份認證,也可以用於信息交換。由於信息會使用密鑰進行數字簽名,因此 JWT 可以被驗證以及信任。
JWT 應用場景
常見的 JWT 應用常見有 JWT 授權和信息交換:
-
• 授權:JWT 被應用最多的場景,用戶登錄後服務端響應一個 JWT,後續的請求都攜帶 JWT 內容,以此驗證用戶身份。使用 JWT 可以進行單點登錄,可以跨域。
-
• 信息交換:因爲 JWT 需要使用密鑰進行簽名,因此使用 JWT 安全的傳輸信息也是一個好方法,簽名可以確保消息發送人沒有問題,確保消息沒有被篡改。
JWT 組成結構
JWT 由小數點分割的三部分組成,如 xxxxx.yyyyy.zzzzz
,這三部分對應的是的標頭(Header)、負載(Payload)、簽名(Signature),每部分使用 Base64Url 進行編碼,
下面是一個真實 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。
-
- 服務器對 JWT 進行簽名,然後將其發送回用戶。
-
- 用戶將 JWT 存儲在客戶端(如 localStorage),並在隨後的請求中隨同發送。如添加到請求頭:
Authorization: Bearer <token>
- 用戶將 JWT 存儲在客戶端(如 localStorage),並在隨後的請求中隨同發送。如添加到請求頭:
-
- 服務器在接收到請求後,驗證 JWT 的簽名並解析其內容,確認用戶的身份,然後返回請求的數據。
-
- JWT 可能在一定時間後過期,用戶需要重新登錄獲取新的 JWT。
JWT 的特點
JWT 有下面幾個特點。
-
1. 緊湊:JWT 設計十分緊湊,結果較小,可以在參數,請求頭中傳輸。
-
2. 自包含:JWT 自身包含了用戶驗證的所需信息,避免了多次查詢數據庫。
-
3. 跨語言:JWT 使用 JSON 格式,現代編程語言都有對 JSON 的支持。
-
4. 安全性:JWT 需要使用密鑰進行數據簽名,密鑰不泄露,JWT 就是安全的。但是因爲 JWT 自包含和 Base64Url 編碼特性,JWT 中的信息可以被直接讀取,因此建議使用 HTTPS 協議。如果對安全性要求較高,還可以對 JWT 內容在進行一次加密(如 AES)。
-
5. 分佈式環境友好:因爲 JWT 在服務端無狀態,因此 JWT 適用於單點登錄,同時可以跨域。
-
6. 不可撤銷:一旦 JWT 簽發了,在有效期內將會一直有效,除非服務器增加額外邏輯來強制撤銷某個 JWT Token,如黑名單機制。
-
7. 性能問題:雖然避免了查詢數據庫,但是服務器仍需對每個請求中的 JWT 進行解碼和驗證,如果請求量巨大,這也可能成爲性能瓶頸。
JWT 最佳實踐
JWT 存在優點,也有很多風險與挑戰,參考前人的最佳實踐可以少走彎路。
-
- 內容緊湊最小化:最小限度的減少 JWT 負載中的內容,避免存儲敏感數據,只存儲重要數據。某些服務器不接受大於 8KB 的請求頭。
-
- 驗證必不可少:每次收到 JWT 都要進行驗證,內容驗證,過期時間驗證。發行者驗證。
-
- 使用 JWT 庫:不要自己編寫 JWT 類庫,密碼學和安全都是非常複雜的東西,使用專業的類庫好過自己編寫。
-
- JWT 過期時間:設計合理的過期時間,因爲 JWT 一旦頒發,無法刪除。過長的有效期存在風險。
總體而言,JWT 提供了一種相對簡單且有效的方式來處理身份驗證問題,但是需要注意 JWT 安全性和細節問題,以確保 JWT 可以在應用中正確且安全地使用。
預告:下一篇文章會介紹如何在 Java 中使用 JWT 進行身份驗證。
參考
-
• https://jwt.io/introduction
-
• https://medium.com/@arunchaitanya/wtf-is-bearer-token-an-in-depth-explanation-60695b581928
-
• https://datatracker.ietf.org/doc/html/rfc7519
引用鏈接
[1]
JWT 在線解碼驗證工具: _https://jwt.io/?_gl=11igv4lh_gaNTkxODM4NDM2LjE3MTA1ODM3NTM.ga_QKMSDV5369*MTcxMDgwOTgyOS40LjEuMTcxMDgxMDgyNC41Ny4wLjA.
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/wIxg55riF03u25CJhJrM5g