網上大多數介紹JWT的文章實際介紹的都是JWS(JSON Web Signature),也往往導致了人們對於JWT的誤解,但是JWT並不等於JWS,JWS只是JWT的一種實現,除了JWS外,JWE(JSON Web Encryption)也是JWT的一種實現。
JWS
-
頭部(Header)
頭部用於描述關於該JWT的最基本的信息
例如:其類型、以及簽名所用的算法等。
JSON內容要經Base64 編碼生成字符串成為Header。 -
載荷(PayLoad)
payload的五個字段都是由JWT的標准所定義的。
iss: 該JWT的簽發者
sub: 該JWT所面向的用戶
aud: 接收該JWT的一方
exp(expires): 什么時候過期,這里是一個Unix時間戳
iat(issued at): 在什么時候簽發的
后面的信息可以按需補充。 JSON內容要經Base64 編碼生成字符串成為PayLoad。 -
簽名(signature)
這個部分header與payload通過header中聲明的加密方式,使用密鑰secret進行加密,生成簽名。
JWS的主要目的是保證了數據在傳輸過程中不被修改,驗證數據的完整性。
但由於僅采用Base64對消息內容編碼,因此不保證數據的不可泄露性。所以不適合用於傳輸敏感數據。
JWE
相對於JWS,JWE則同時保證了安全性與數據完整性。 JWE由五部分組成:
JWE的計算過程相對繁瑣,不夠輕量級,因此適合與數據傳輸而非token認證,但該協議也足夠安全可靠,用簡短字符串描述了傳輸內容,兼顧數據的安全性與完整性
- JWE組成
具體生成步驟為:
JOSE含義與JWS頭部相同。
生成一個隨機的Content Encryption Key (CEK)。
使用RSAES-OAEP 加密算法,用公鑰加密CEK,生成JWE Encrypted Key。
生成JWE初始化向量。
使用AES GCM加密算法對明文部分進行加密生成密文Ciphertext,算法會隨之生成一個128位的認證標記Authentication Tag。 6.對五個部分分別進行base64編碼。
1. jwt
-
VS狀態保持機制
1.APP不支持狀態保持
2.狀態保持有同源策略, 默認無法跨服務器傳遞(nginx可以處理) -
JWT不會對數據進行加密, 所以數據中不要存放有閱讀價值的數據
-
不可逆加密
- md5 sha1 sha256
- 主要用於數據認證, 防止數據被修改
消息摘要 MD
- 哈希算法:
將任意長度內容轉為定長內容, 且相同內容的哈希值始終相同, 不同內容的哈希值不同(極小概率出現碰撞)
由於其唯一性, 一般將數據的哈希值稱為數據的摘要信息, 稱為數據的"指紋", 用於檢測數據是否被修改 - 代表算法 sha1 sha256 md5
- 缺點:哈希算法是公開的, 如果可以獲取到明文, 就可以窮舉出使用的算法
消息認證 MA ( JWT一般會采用消息認證機制)
哈希算法基礎上混入秘鑰, 防止哈希算法被破解, 避免簽名被偽造
- 代表算法 hmacsha256
2. PyJWT (重點)
- 安裝
pip install PyJWT
import jwt
from jwt import PyJWTError
from datetime import datetime, timedelta
payload = { # jwt設置過期時間的本質 就是在payload中 設置exp字段, 值要求為格林尼治時間
"user_id": 1,
'exp': datetime.utcnow() + timedelta(seconds=30)
}
screct_key = "test"
# 生成token
token = jwt.encode(payload, key=screct_key, algorithm='HS256')
print(token)
# 驗簽token 返回payload pyjwt會自動校驗過期時間
try:
data = jwt.decode(token, key=screct_key, algorithms='HS256')
print(data)
except PyJWTError as e:
print("jwt驗證失敗: %s" % e)
3. 數字簽名 (拓展)
- 消息認證存在缺點
- 之前沒有對服務器返回的數據進行驗簽, 無法確認數據是否被修改(服務器身份是否合法)
- 將秘鑰交給客戶端, 客戶端才可以驗簽服務器返回的數據是否被修改
- 但是客戶端安全性較差, 一旦秘鑰泄露, 仍然可以偽造簽名
- 利用非對稱加密對摘要信息進行加密, 避免摘要信息被偽造
- 非對稱加密采用秘鑰對
- 公鑰和私鑰
- 公鑰加密, 私鑰解密
- 私鑰加密, 公鑰解密
- 私鑰可以推出公鑰, 公鑰無法推出私鑰
- 發送者使用私鑰對數據摘要加密(簽名), 接收者使用對應的公鑰解密, 然后對數據進行哈希處理, 比對摘要信息是否一致(驗簽)
- 代表算法 RSA
- 使用場景
- 安全級別要求比較高的系統, 如銀行等
- 優點
- 客戶端不會像消息認證一樣保存秘鑰, 而是保存了非對稱加密的公鑰, 即使客戶端被破解, 公鑰被獲取, 也無法通過公鑰生成合法的簽名
- 缺點
- 效率低
- 使用openssl 生成RSA秘鑰對
# 生成私鑰,指定私鑰的長度為2048bit 1024基本安全, 2048非常安全
openssl genrsa -out rsa_private_key.pem 2048
# 根據私鑰生成對應的公鑰
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key_2048.pub
# 私鑰轉化成pkcs8格式, 非必須,pkcs8格式解析起來更方便
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt > rsa_private_key_pkcs8.pem
- 安裝RSA類庫
pip install cryptography