1. 程式人生 > >Web安全通訊之Token與JWT

Web安全通訊之Token與JWT

https://www.jianshu.com/p/ca7afbd392e9

本文用於個人學習筆記

Token

什麼是token

Token是服務端生成的一串字串,以作客戶端進行請求的一個令牌,服務端根據令牌獲取客戶端的身份資訊。
舉個栗子:

http://www.example.com/demo?token=15qwc87wq336scwWFSC2sc1w

為什麼要用token

網際網路時代資訊保安驗證放在首要的地位,對於敏感的資訊(如賬號密碼等等)明文的出現次數越少越好。

我們都知道,HTTP協議是一種無狀態的協議,這就意味著當我們嚮應用服務端提供了使用者名稱和密碼進行使用者認真後,下次請求還是要再進行使用者認證,而且服務端又不知道發起請求是誰。按照這個思維,假如每個請求都帶有敏感資訊,即使進行加密,但是這就增加暴露頻率,並且服務端頻繁對每個請求的身份資訊進行資料查詢驗證,這是個很大的開銷,顯然不是我們想要的結果。

為了我們登入後讓服務端“記住”我,下次發出請求服務端識別哪個使用者傳送的,token令牌能解決http無狀態的問題,這時候你會覺得SESSION不也一樣嗎?別急,下面會說到。token就像我們的身份證,客戶端一旦得到服務端響應的token後本地快取,之後每次請求帶上token就行了,重要的是開發者可以在token上自定義資訊(如UUID),並且是加密的,服務端就減少資料查詢驗證身份的開銷了。

與傳統的SESSION有什麼區別

如果您還不瞭解session,請先自行百度學習,這裡我簡單介紹下:

session 是一種HTTP儲存機制,目的是為無狀態的HTTP提供的持久機制。

  • Session一般只提供一種簡單的認證ID,即JSESSIONID,使用者資料只儲存在服務端上,因此JSESSIONID尤為重要需要嚴格保密,這導致了session的弊端:如果web伺服器做了負載均衡,那麼下一個操作請求到了另一臺伺服器的時候session會丟失。
  • Session:使用者資料儲存在服務端;Token:客戶端的 cookie 或本地介質儲存。
  • Session 更加適合在瀏覽器上應用,對於開發API介面 Token 是不錯的選擇。
  • 一旦伺服器掛了 sessionid 在服務端記憶體中對映資訊丟失了, token 具有自帶性,狀態還存在。
  • Token 安全性好,有簽名能防止資訊篡改、監聽、重放攻擊。
  • Token 能進行授權操作,Session 不可以。
  • Token 不再依賴於 Cookie,所以你就不需要考慮對 CSRF(跨站請求偽造)的防範。
  • HMACSHA256 計算的 Token 驗證和解析的費時比資料庫查詢 Session 多。

token身份驗證流程

  • 客戶端使用使用者名稱和密碼請求登入驗證
  • 服務端接受請求,進行身份驗證
  • 驗證成功後,服務端會簽發一個 Token,再把這個 Token 傳送給客戶端
  • 客戶端收到 Token 後把它存起來
  • 客戶端每次向服務端請求時候就帶上 Token
  • 服務端收到 Token 後,去驗證 Token ,如果驗證通過,執行業務邏輯

服務端中跟Token有關的問題

  • 或許你們會想到,Token具有自帶性,使用者的線上狀態不可能存在Token中,那怎麼知道使用者是否線上呢 ?
    其實服務端中每個Token可以與UUID形成對映對儲存在伺服器上面,當用戶登出操作時,刪除UUID與Token的鍵值對,所以查詢不到表示下線了
  • 如何存查刪 Token ?
    我們可以把Token資訊快取在記憶體中,比存在資料庫中的好處是讀取速度快,開銷小,壞處是一旦斷點資料全沒了,不過token重新認證操作獲取就有一個了。基於快取記憶體中,memcached、redis,KV方式很適合對token查詢的需求。

JWT(Json Web Token)

官網地址:https://jwt.io/

jwt github:https://github.com/jwtk/jjwt

什麼是JWT(Json Web Token)

Json web token (JWT), 是為了在網路應用環境間傳遞宣告而執行的一種基於JSON的開放標準。該token被設計為緊湊且安全的,特別適用於分散式站點的單點登入(SSO)場景。JWT的宣告一般被用來在身份提供者和服務提供者間傳遞被認證的使用者身份資訊,以便於從資源伺服器獲取資源,也可以增加一些額外的其它業務邏輯所必須的宣告資訊,該token也可直接被用於認證,也可被加密。也就是說JWT是Token的一種表述性宣告規範。

如果你不清楚JSON請自行學習

JWT長什麼樣子

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3OHNhd2RmZjUiLCJzdWIiOiJ4aWFvdGlhbnRpYW4iLCJpYXQiOjE0OTgwMzE0NDIsImlzcyI6IjEyMi4xMTQuMjE0LjE0NyIsImV4cCI6MTQ5ODAzMjY0Mn0.0h_kDhyZLhnt8TRgbLsOnVT8eOUAqgFTEZP-XgIGuA

上面字串都是用Base64編碼後,發現結構類似:xxx.yyy.zzz

JWT的結構

JWT包含了三個部分,分別用.分割開來,分別是:

  • Header 頭部
  • Payload 負載
  • Signature 簽名
// 1.Header,包含JWT基礎宣告,加密演算法與類別
{
    "alg": "HS256", // 加密演算法
    "typ": "JWT"    // 類別
}
// 2.Payload,存放有效資訊的地方
// 包含 Claim ,它可以一些實體(通常指的使用者)的狀態和額外的元資料,有三種類型
// 2.1.Reserved claims JWT標準裡面定好的claim,內容如下:
// 2.2.Public claims 
// 2.3.Private claims
// 建議的 Claims 不是強制使用的,完全可以按照自己的需求自定義playload,如果是自定義的claims名,您使用的實現庫是不會主動去驗證它們的
{
    "aud": "uuu",   // 接受者
    "iss": "xxx",   // 簽發者
    "exp": "1498499261660", // 過期時間
    "sub": "yyy",   // 主題
    "iat": "1498459261660", // 簽發時間
    "jti": "",  // JWT的唯一身份標示
    "nbf": "1498459261660", // 定義在什麼時間之前,該jwt都是不可用的
    ...
}
// 3.Signature,簽名,根據Header定義的演算法和私鑰組合加密
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

JWT簽發與驗證流程

  1. 服務端根據業務需求宣告 Header 和 Playload
  2. 將 Header 和 Playload 分別生成 Json 字串
  3. Header 和 Playload 分別進行base64編碼,用 . 分隔開來,組成 JWT 的第一和第二部分,例如:
    eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3OHNhd2RmZjUiLCJzdWIiOiJ4aWFvdGlhbnRpYW4iLCJpYXQiOjE0OTgwMzE0NDIsImlzcyI6IjEyMi4xMTQuMjE0LjE0NyIsImV4cCI6MTQ5ODAzMjY0Mn0
  4. 得到第3步生成的字串,根據 Header 裡面 alg 指定的簽名演算法生成出來形成 JWT 的 Signature 部分。演算法不同,簽名結果不同,常用的值以及對應的演算法如下:

     

  5. 第4步生成的 Signature 組成 JWT 的第3部分,用 . 分隔組成完整的 JWT:
    eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3OHNhd2RmZjUiLCJzdWIiOiJ4aWFvdGlhbnRpYW4iLCJpYXQiOjE0OTgwMzE0NDIsImlzcyI6IjEyMi4xMTQuMjE0LjE0NyIsImV4cCI6MTQ5ODAzMjY0Mn0.0h_kDhyZLhnt8TRgbLsOnVT8eOUAqgFTEZP-XgIGuA
  6. 到這裡服務端簽發流程結束
  7. 客戶端得到 JWT 後存起來,每次請求帶上 JWT 字串
  8. 服務端收到請求攜帶的 JWT ,開始進入驗證流程
  9. 對 JWT 的完整性進行驗證,使用 base64 對 Header 進行解碼,知道 JWT 使用什麼簽名
  10. 重複第4步對 Header 和 Playload 再做一次簽名
  11. 比較這個簽名是否與 JWT 本身攜帶的簽名完全相同,只要不同,就可以認為該 JWT 是被篡改過的,驗證失敗,驗證流程結束
  12. 如果相同,使用 base64 對 Playload 進行解碼,再進行業務邏輯處理,此時驗證成功,驗證結束。

注意

  • Playload 不要存放敏感資訊,因為該部分用base64編碼,在客戶端是可解的;
  • 服務端保護好secre私鑰,一旦客戶端得帶私匙就可以自己簽發 JWT 了;
  • 在網路層面上 token 明文傳輸的話會非常的危險,所以建議一定要使用 HTTPS ,並且把 token 放在 post body 裡。PS:正在準備下一篇關於 HTTPS 的筆記。

PS:

  • 推薦個 線上簽名工具 用於除錯
  • 超讚強大的API除錯工具 Postman,在谷歌瀏覽器外掛就搜尋得到,不過需要翻牆,這個百度好多種方法



作者:王蒼天
連結:https://www.jianshu.com/p/ca7afbd392e9
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。