JWT认证方案与禁用令牌策略
Posted yblackd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JWT认证方案与禁用令牌策略相关的知识,希望对你有一定的参考价值。
1.1 jwt
-
对比状态保持机制
-
APP不支持状态保持
-
状态保持有同源策略, 无法跨服务器传递
-
-
不可逆加密
-
md5 sha1 sha256
-
主要用于数据认证, 防止数据被修改
-
-
消息摘要 MD
-
通过哈希算法将任意长度内容转为定长内容, 且相同内容的哈希值始终相同, 不同内容的哈希值不同(极小概率出现碰撞)
-
由于其唯一性, 一般将数据的哈希值称为数据的摘要信息, 称为数据的"指纹", 用于检测数据是否被修改
-
代表算法 sha1 sha256 md5
-
缺点
-
哈希算法是公开的, 如果可以获取到明文, 就可以穷举出使用的算法
-
-
-
消息认证 MA
-
哈希算法基础上混入秘钥, 防止哈希算法被破解, 避免签名被伪造
-
代表算法 hmacsha256
-
JWT一般会采用 消息认证 机制
-
一般的web应用, 不会将秘钥交给客户端 ,也就表示
客户端不会验签服务器的身份
-
-
缺点
-
一旦秘钥泄露, 仍然可以伪造签名
-
-
-
数字签名
-
利用非对称加密对摘要信息进行加密, 避免摘要信息被伪造
-
非对称加密采用秘钥对
-
公钥和私钥
-
公钥加密, 私钥解密
-
私钥加密, 公钥解密
-
私钥可以推出公钥, 公钥无法推出私钥
-
-
发送者使用私钥对数据摘要加密(签名), 接收者使用对应的公钥解密, 然后对数据进行哈希处理, 比对摘要信息是否一致
-
代表算法 RSA
-
使用场景
-
安全级别要求比较高的系统, 如银行等
-
-
优点
-
客户端不会像消息认证一样保存秘钥, 而是保存了非对称加密的公钥, 即使客户端被破解, 公钥被获取, 也无法通过公钥生成合法的签名
-
-
缺点
-
效率低
-
-
1.2 PyJWT
-
安装
pip install PyJWT
import jwt
from datetime import datetime, timedelta
from jwt import PyJWTError
?
# 包装数据 jwt的规范中要求通过exp参数来设置有效期, 要求有效期使用格林尼治时间
payload = {‘payload‘: ‘test‘, ‘exp‘: datetime.utcnow() + timedelta(seconds=30)}
?
key = ‘secret‘
# # 生成jwt
# token = jwt.encode(payload, key, algorithm=‘HS256‘)
# print(token)
?
?
token = b‘eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXlsb2FkIjoidGVzdCIsImV4cCI6MTU2MjgwOTkzMn0.BSc0A2ibdjHTlmW7wtWfj5ZGkny8RX8tV12313‘
# 验证jwt pyjwt内部对有效期进行了验证, 如果超过时间, 会报错
try:
ret = jwt.decode(token, key, algorithms=‘HS256‘)
print(ret)
except PyJWTError as e:
print("jwt认证失败") -
数字签名
-
使用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.pemimport jwt
?
"""服务器使用私钥生成签名 对数据摘要加密 称为 签名"""
# with open(‘rsa_private_key_pkcs8.pem‘, ‘rb‘) as f:
# private_key = f.read()
# # 生成数字签名
# encoded = jwt.encode({‘some‘: ‘payload‘}, private_key, algorithm=‘RS256‘)
# print(encoded)
?
?
"""客户端用公钥验签"""
encoded = b‘eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzb21lIjoicGF5bG9hZCJ9.S3gxuFvPiYk2752deTDm6qupj53S0b_-WvFZLKnWzLgDTFjFF_uiwmI6GAT1mKaNvWIyxFQ1PMUPxjkdLuJpGbN3hpHM_eKaQNm_RTvY8UUh6tvq8kpH4FAF2WOglwQK9f3nS8R73PrYhQFDHcfSEBWoJJPva_Pb3YEPMawUTPmd8aeS2uma4n9JqaZwCWm1GE-6S0lKNHp7ZWMlxb5E1R_FgSLIiE3qQq-mWsweyMRtsyCBCaB1W6Y24EYuDW0KHu6k6jGZdwwABVuwyKXKVTTf_XvxM3X41ggpY6mkarSXZsF3-Aw_jWOUBHy9VBHfPCeklur6oMfyGT4FQzkcQQ‘
?
?
with open(‘rsa_public_key_2048.pub‘, ‘rb‘) as f:
public_key = f.read()
decoded = jwt.decode(encoded, public_key, algorithms=‘RS256‘)
print(decoded)
-
1.3 JWE
-
可逆加密
-
对称加密
-
代表算法 des 3des aes
-
快
-
-
非对称加密
-
代表算法 RSA
-
慢, 不适合大型数据加密
-
加密时, 一般公钥加密, 私钥解密, 与签名相反
-
一般私有只有一方持有, 公钥则可以多方持有(公钥公开)
-
私钥唯一, 使用私钥签名, 公钥验签, 可以保证签名者身份唯一
-
加密时, 私钥解密, 保证可以解密者唯一
-
-
生成方式 openssl
-
-
主要用于数据加密
-
-
最佳方案JWE
-
传输的数据使用对称加密, 生成数据密文, 对称加密秘钥是随机的
-
为了防止数据篡改, 对数据密文进行摘要认证(一般使用消息认证), 摘要认证的秘钥也是随机的
-
对称加密的秘钥 和 摘要认证的秘钥 使用非对称加密进行处理
-
JWE的耗时远高于JWS
-
用于金融领域
-
-
安装
pip install authlib
from authlib.jose import JWE
from authlib.jose import JWE_ALGORITHMS
?
# 创建JWE对象
jwe = JWE(algorithms=JWE_ALGORITHMS)
?
# 设置头部信息 指定算法
protected = {‘alg‘: ‘RSA-OAEP‘, ‘enc‘: ‘A256GCM‘}
# 明文数据
# payload = b‘hello‘
# 获取到非对称加密的公钥
# with open(‘rsa_public_key_2048.pub‘, ‘rb‘) as f:
# key = f.read()
?
# 加密数据
# s = jwe.serialize_compact(protected, payload, key)
# print(s)
?
?
?
s = b‘eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.whFm08vAVhN-BvuRq3BXOqUcw3NnFAAHVswHuqc-JQdixCODernvAQdCDQSlEOmJHhNNm_h1bgji2fctSxY-PDnKv17yCX7IJhDzKLY443NysapeYzku8IAOTPuYV-mE5rk0nCP_u76o8i-kAhmV0OgO19WXgDftqL84zypeBIRmV4w5KaTLGWhU7uOpszHokkTcf1TdXChu7dRcStIekb68-FP5ZmOhAKk8azILH871u290LbIDVowp69tARQJzEzAawiQ7kPmj03XtLQEF6SZgrhH585jQK_hh-NkiMVUiW8GCYPdGLKH8WQoaZionZXrK1ISdAc6RSa3cEiwzGA.AA9nf4X2ftxbp8Ec.kHgOI1E.9Oa_IHyqfdLJ1mCzXopI9g‘
?
with open(‘rsa_private_key_pkcs8.pem‘, ‘rb‘) as f:
# 获取非对称加密的私钥 用于解密
key = f.read()
data = jwe.deserialize_compact(s, key)
jwe_header = data[‘header‘]
payload = data[‘payload‘]
print(jwe_header, payload)
1.4 refresh token
1.4.1 刷新token实现流程
?
-
特点
-
访问令牌虽然使用频繁, 但是有效期短, 只有两个小时
-
刷新令牌有效期长, 但是访问次数少, 可以减少泄露的风险
-
1.4.2 登录接口
-
接口设计
-
视图逻辑
-
生成令牌
1.4.3 访问控制
-
对于所有的接口都需要获取认证信息 使用请求钩子实现
-
对于指定的接口进行访问控制 使用装饰器
-
请求钩子和装饰器
1.4禁用令牌
-
需求场景
-
用户修改密码, 需要颁发新的token, 禁用还在有效期的旧token
-
后台封禁用户
-
-
逻辑
-
禁用旧密码的令牌
-
以上是关于JWT认证方案与禁用令牌策略的主要内容,如果未能解决你的问题,请参考以下文章
如何在使用 Spring Boot 的 JWT 令牌时禁用同一用户帐户的多个登录