JOSE(JSON Object Signing and Encryption) 定義了一系列的 RFC 標準
目前有:
- JSON Web Signature
- JSON Web Encryption
- JSON Web Key
- JSON Web Algorithm
- JSON Web Token
JWT (JSON Web Token) 算是集前面大成者(?)
詳細的介紹可以看這裡,這邊直接從 JWT 切入
每個 JWT 稱為一個 claim,每個 claim 組成為分別為 header.payload.signature (注意它使用 ‘.’ 來虛隔三者)
Header
{
"typ": "JWT",
"alg": "HS256"
}
typ 代表使用 JWT
alg 代表signature 演算法使用 HS256
Payload
{
"iss": "",
"sub": "",
"aud": "",
"exp": "",
"nbf": "",
"iat": "",
"jti": ""
}
payload 中的 data 有明確的欄位定義
因為沒有很重要所以就不做說明
Signature
因 header 裡 alg 所標示的演算法而有所差異
Example
以上每個部份都要使用 bas64 encode (將截尾用於 padding 的 = 移除),之後使用點(dot)來做連接
這裡是 JWT.io 給出的範例
header = {"alg": "HS256", "typ": "JWT"}
pylaod = {"sub": "1234567890", "name": "John Doe", "admin", true}
signature = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), SECRET)
上述資料處理後長相如下
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
Problem
- none algorithm
這裡有個有趣的地方,header 部份的 alg 是可選的,之後應該由 server 端以 alg 所標明的方式驗證
但若 alg = none, 意思為不使用任何演算法處理,但格式只要正確此 JWT 仍屬有效(validate)
此處 RFC 7519 已有標明屬於 unsecrure JWT,但實做時可能會沒注意導致 header 被竄改以後 token 可被偽造
以下為 validate 的 JWT
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.
- RSA or HMAC
alg 除了 HS256 還有 RS256 等其他的選項可選,假設現在我的 server 給 client 是標明使用 RS256 的驗證方式
當 alg 為 RS256 時,token 使用 private key 來簽發,但是 server 驗證的時候使用 public key 來驗證
如果將 public key 釋出自己保留 private key 的話,則只有你可以簽發 token,其他人則可以利用 public key 來驗證
這個 token 是否由你所簽發的,在實做的時候可能看起來像這樣
verify(token,verification_key)
當 server 使用 HMAC signature 時 verification_key ,function 可能會長這樣
verify(client_token, server_HMACSecretKey)
當 server 使用非對稱式演算法時,verification_key 會成為 public key,function 驗證可能長這樣
verify(client_token, serverRSAPublicKey)
因此若 header alg 從 RS256 被竄改成 HS256 則 server 會將 public key 認為是一個 HMAC secret key
問題來了 public key 是大家都可以知道的,所以 token 在這種情況下可以被 server 正確的驗證
因此 token 就可以任意偽造,視 token 的用途所造成的傷害不一。
可以在 JWT.io 了解各個語言函式庫的支援程度及安全的版本。