背景
參考 開放api接口簽名驗證 ,REST接口安全認證方式對比:API Key vs OAuth令牌 vs JWT
微服務開發過程中,寫開放的API接口時,可能會帶來如下安全問題:
- 請求源是否合法
- 請求參數是否被篡改
- 請求的唯一性
為了避免以上安全性問題,保證數據在通信時的安全性,我們需要驗證使用者的身份。驗證使用者身份有多種方式:session , token等。在微服務中,用戶直接調用API獲取資源,這時候就需要token來驗證使用者身份,保護數據安全。這篇文章主要講token ----json web token。
以下內容摘自 以 JSON Web Token 替代傳統 Token
session
在傳統網站中,會用session來辨別使用者身份,辨別使用者是否登陸。由於session只會被服務器端知道,所以可以在session中保存一些機密資料以供之后驗證使用。
session存在的問題
- 具狀態性:假設有兩台服務器 通過負載均衡 來互相處理 用戶請求,由於session是存儲在服務器端,第一次用戶登陸時,由Server1 處理,那么session會存在Server1。如果下一次,用戶請求 被負載均衡 指派Server2來處理,那么session在Server2不存在,所以用戶就需要重新登陸一次。(這個問題可以解決,暫不討論)
- 容易受 跨網域請求偽造攻擊:session存在服務器端,所以用戶 在發送請求時幾乎不用提供什么。所以很可能用戶提供了一個刪除文章的連接給服務器,服務器就刪除了文章。
Token
Token可以解決 session 容易受 跨網域請求偽造攻擊的問題,並且可以在多個服務器上 跨域使用。
- 什么是token:用戶登陸成功時,會得到一個數字字符串,這個串看起來毫無意義,可是對應資料庫中使用者的身份。這個串就是token
- 無狀態性:當服務器接收到token時,會解密token,對比數據庫,然后就會知道這個token是否合法,對應哪個用戶,並獲取這個用戶的相關資料等。由於多個服務器共享一個 數據庫,所以就不存在session 只存在 在一個服務器的問題。
- 避免 受 跨網域請求偽造攻擊:因為用戶需要主動提供token,非法攻擊 不會擁有合法的token,所以不能請求成功。
JWT json web token 取代傳統token
- 相比token需要從數據庫中比對用戶是否合法,jwt 可以存放資料,不需要數據庫來存儲用戶資料。直接把用戶資料存放在「Token」中,所以也就省去了額外的數據庫開銷
JWT json web token 的構成:
- Header 頭部:JWT 的頭部包含兩部分,token類型和采用的加密算法。這些內容通過 Base64 編碼就得到JWT的頭部 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
{
"alg": "HS256",
"typ": "JWT"
}
- Payload 負載:JWT的標准所定義的幾個基本字段 + 我們在業務處理中需要用到的字段,如用戶賬號,昵稱等,這樣就不再需要去數據庫找,不要放密碼。將這部分通過 Base64 編碼就得到第二段字符串 eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
- JWT的標准所定義的幾個基本字段
- issuer: 該JWT的簽發者
- subject: 該JWT所面向的用戶
- audience: 接收該JWT的一方
- expiration(expires): 什么時候過期,這里是一個Unix時間戳
- issueAt(issued at): 在什么時候簽發的
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
- Signature 簽名:這部分的算法是由上面兩部分內容的 Base64 以點(
.
)組合起來,並以密碼加密得到簽名TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), "secret")
以上3部分就組成了 json web token = 標題.內容.簽名
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
由於生成簽名的密碼是存在服務器端的,所以就不怕別人篡改JWT,因為別人篡改的JWT 不會被服務器識別。