基于JWT的token弱密钥爆破

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。直接根据token取出保存的用户信息,以及对token可用性校验,大大简化单点登录。

JWT=header+payload+signature(以.相隔)

例:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzYxMTk2NTYsInVzZXJuYW1lIjoiemRqIiwicGFzc3dvcmQiOiIxMjMifQ.ud_qtIYt3QywJkmjPZIXVPaW3SnWCFj9dLVYa7iTEIg

下面详细介绍一下每个部分。

头部(Header)

用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。

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

BASE64编码后为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

载荷(playload)

(1)标准中注册的声明(建议但不强制使用)

(2)公共的声明

(3)私有的声明(过期时间,用户名等信息)

{"exp":1576119656,"username":"zdj","password":"123"}

BASE64编码后:eyJleHAiOjE1NzYxMTk2NTYsInVzZXJuYW1lIjoiemRqIiwicGFzc3dvcmQiOiIxMjMifQ

签名(signature)

header(base64)+payload(base64)使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分

ud_qtIYt3QywJkmjPZIXVPaW3SnWCFj9dLVYa7iTEIg

注:secret是保存在服务器端的签名私钥,就是我们今天的主角;

基于java实现JWT:

生成token:

public static String Generatetoken(String username, String password) {

String token = "";

try {

// 过期时间

Date date = new Date(System.currentTimeMillis() + EXPIRE_DATE);

// 秘钥及加密算法

Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);

// 设置头部信息

Map header = new HashMap();

header.put("typ", "JWT");

header.put("alg", "HS256");

// 携带username,password信息,生成签名

token = JWT.create().withHeader(header)

.withClaim("username", username)

.withClaim("password", password).withExpiresAt(date)

.sign(algorithm);

} catch (Exception e) {

e.printStackTrace();

return null;

}

return token;

}

校验token:

public static boolean verify(String token) {

try {

Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);

JWTVerifier verifier = JWT.require(algorithm).build();

System.out.println("验证token:" + token);

DecodedJWT jwt = verifier.verify(token);

return true;

} catch (Exception e) {

e.printStackTrace();

return false;

}

}

生成的token为

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzYxMTk2NTYsInVzZXJuYW1lIjoiemRqIiwicGFzc3dvcmQiOiIxMjMifQ.ud_qtIYt3QywJkmjPZIXVPaW3SnWCFj9dLVYa7iTEIg

综上,我们要伪造token,首先要拿到TOKEN_SECRET,才可以伪造签名,token才能校验通过。

pyjwt 库,可通过 jwt.decode(jwt_str, verify=True, key=key_)

进行签名校验,但导致校验失败的因素不仅密钥错误,还可能是数据部分中预定义字段错误(如,当前时间超过 exp),也可能是 JWT字符串格式错误等等,所以,借助 jwt.decode(jwt_str, verify=True, key=key_) 验证密钥 key_:

1.若签名直接校验失败,则 key_ 为有效密钥;

2.若因数据部分预定义字段错误

(jwt.exceptions.ExpiredSignatureError,

jwt.exceptions.InvalidAudienceError,

jwt.exceptions.InvalidIssuedAtError,

jwt.exceptions.InvalidIssuedAtError,

jwt.exceptions.ImmatureSignatureError)导致校验失败,说明并非密钥错误导致,则 key_ 也为有效密钥;

3.若因密钥错误(jwt.exceptions.InvalidSignatureError)导致校验失败,则 key_ 为无效密钥;

4.若为其他原因(如,JWT 字符串格式错误)导致校验失败,根本无法验证当前 key_ 是否有效。

按此逻辑,快速实现 JWT 密钥暴破功能,代码如下:

爆破弱密钥脚本

准备好key.txt字典,目标token为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzYxMjE1NDcsInVzZXJuYW1lIjoiemRqIiwicGFzc3dvcmQiOiIxMjMifQ.mkCLR5Kje9x-z8hRgWBMxnQm8hknOwV1Zd8uSZa3rQY,运行脚本进行爆破:

无法获取到key
获取到key

总结

因此,开发员要十分注意token的密钥强度,不然攻击者可以通过pyjwt爆破得到token密钥,通过header和payload进行signature,进而伪造token发生跨域攻击。

你可能感兴趣的:(基于JWT的token弱密钥爆破)