JWT JSON Web Token 驗證簡述

JSON Web Token, 或JWT (jot) 簡單來說, 是一種傳送驗證授權的標準。 為什麼我們需要JWT? 從前我們在驗證使用者身份後,可能會將使用者資訊存在於session當中,這種做法有幾種缺點:

  • 造成Server記憶體負擔
  • 如果需將Application掛載於多台Server上,必須要同步所有的Server的session
  • 無法處跨平台授權問題

於是,JWT誕生了。因為Http 的請求是無狀態的(stateless)因此我們必須將sessiont儲存在Server Side. 我們利用JWT的技術標準,由Server Side產生一組token給予Client Side, 再由Client Side保存好,並在每一次Request將token帶入。 這間接解決了cookie的缺點,不易被竄改。

談到這我們就可以來說明token的優點:

安全性

如上述所說明, 除了token沒機會被修改以外, 我們也可以要求token的時效性來提高安全性。

擴充性

我們可以利用token來分享權限給予第三方使用者

解決跨域問題

傳統cookie在登入的時候必須在所有domain寫入,但token只要實作相同的驗證機制即可


說了這麼多,我們還是要來談論,如何實作JWT機制

JWT主要分為三個部分:

  • header (標頭)
  • payload(訊息內容)
  • signature(簽章)

最終組成一個Token:

{header}.{payload}.{signature}

 

Header的內容為 JSON物件:

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

Header 主要是說明JWT將用何種演算法建立。

 

Payload的內容也是JSON物件:

{
 "sub": "1234567890", 
 "name": "John Doe", 
 "admin": true
}

Payload主要承載使用者需要的資訊,官方的HandBook有說明沒有硬性規定哪些必要屬性。
但仍舊可以歸納出幾個特別的要求:

  • iss:    issuer,帶有機密資料的字串或是URI,可明確指出是由誰發行此JWT
  • sub:  subject,帶有機密資料的字串或是URI,說明JWT的內容
  • aud: audience,帶有機密資料的字串或是URI或是陣列,指出JWT的受眾
  • exp: expiration,代表特定時間的數字,依循POSIX定義的"seconds since epoch"格式,明確指出JWT的過期時間
  • nbf: not before,與exp相反,依循POSIX定義的"seconds since epoch"格式,明確指出JWT的的開始生效日期
  • iat: issue at (time),與exp和nbf格式相同,為JWT的發行時間
  • jti: JWT id,識別此JWT的唯一字串

 

JSON Web Signatures 大概是JWT 最重要的特性之一,先前說過JWT是由Header.Payload.Signature組成,
大概會是類似下面的範例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. (header)
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.(payload)
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ(signature)

依據JWT 規範,有數種簽章演算法可用,因此會有多種不同的解譯。 JWT要求單一演算法以支援相同實作

  • HMAC using SHA-256,在JWT中稱作HS256
  • RSASSA PKCS1 v1.5 using SHA-256,在JWT稱作RS256
  • ECDSA using P-256 and SHA-256,在JWT稱作ES256

JWA為JSON Web Algorithms的縮寫,還有許多演算法就不在此詳列。

HMAC-based的簽章演算法範例如下:

const encodedHeader = base64(utf8(JSON.stringify(header)));
const encodedPayload = base64(utf8(JSON.stringify(payload))); 
const signature = base64(hmac(`${encodedHeader}.${encodedPayload}`,secret, sha256));
const jwt = `${encodedHeader}.${encodedPayload}.${signature}`;

 獲得jwt後,即可傳送至Client Side保存,每次發送request即帶上該token。  Server Side可以用middle ware解析並驗證token。 如此一來即可輕鬆確認使用者身份,亦可減輕Server負擔。 當然實務上的實作還有很多細節要交代,在此只是做為簡述,想了解可進一步至 https://jwt.io/ 的網站下載HandBook來詳讀。