flask项目--认证方案Json Web Token(JWT)
网上大多数介绍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