JWT
定义
JWT(JSON Web Token)是一种用于在各方之间传递信息的紧凑且自包含的方式。它们通常用于认证和授权。
JWT 由三个部分组成:头部(Header)、载荷(Payload)和签名(Signature)。这三个部分一起编码成一个字符串,使用点(.)分隔。
头部(Header)
头部通常包含两个部分:令牌的类型(JWT)和所使用的签名算法(如 HMAC SHA256 或 RSA)。
示例:
1 | { |
载荷(Payload)
载荷部分包含声明(claims)。声明是关于实体(通常是用户)和其他数据的陈述。有三种类型的声明:
- 注册声明(Registered claims):这些是预定义的声明,如 iss(发行者)、exp(过期时间)、sub(主题)、aud(观众)等。
- 公共声明(Public claims):这些可以自定义使用,但应避免冲突。
- 私有声明(Private claims):这些是自定义的声明,只有参与方之间共享的信息。
示例:
1 | { |
签名(Signature)
签名部分是为了确保令牌未被篡改。它通过将头部、载荷和一个密钥(使用 HMAC SHA256 算法)或 RSA 私钥进行编码生成。
签名的生成步骤:
- 将头部和载荷进行 base64url 编码。
- 连接两个编码后的字符串,中间用点(.)分隔。
- 使用指定的算法和密钥对连接后的字符串进行签名。
- 例如,对于 HMAC SHA256:
1 | HMACSHA256( |
工具
jwt编码脚本
1 | import jwt |
jwt在线加解密https://jwt.io/
jwt-cracker
jwt-cracker 是一种工具,用于破解或猜测 JWT(JSON Web Token)的签名密钥。
https://github.com/lmammino/jwt-cracker
使用方法:
jwt-cracker -t jwt -a (暴力)
jwt-cracker -t jwt -d rockyou.txt (字典)
利用
无加密算法(none)
这种情况可以直接将jwt解base64编码得到明文,然后修改部分数据后再重新base64编码回去即可实现伪造身份。
例题:ctfshow web345
dirsearch扫到/admin/index.php
抓包拿到jwt base64解码得到信息
{"alg":"None","typ":"jwt"}?[{"iss":"admin","iat":1720167869,"exp":1720175069,"nbf":1720167869,"sub":"user","jti":"a2fc934dcc24f6579b03f41f65e6a2bc"}]
修改sub里的user改为admin再重新发包得到flag
[{"iss":"admin","iat":1720167869,"exp":1720175069,"nbf":1720167869,"sub":"admin","jti":"a2fc934dcc24f6579b03f41f65e6a2bc"}]
密钥泄露
前提:网站可能将密钥放在后台中没有删除,通过dirsearch等工具查出
HS256
HS256使用公钥进行加解密
获取到公钥即可进行jwt数据篡改
RS256
RS256私钥加密,公钥解密
获取到私钥即可进行jwt数据篡改
弱密码爆破
前提:有些服务器使用弱口令密码作为加密密钥使用
例题:ctfshow web348
抓包拿到jwt,在https://jwt.io解密发现存在HS256加密,密码未知。
使用jwt-cracker 暴力破解得到密码:aaab
修改sub里的user改为admin再重新发包得到flag
修改加密算法
前提:服务器jwt支持多种加密算法
例题:ctfshow web350
源码包里找到public.key(公钥),而抓包得到的jwt是RS256加密,需要的是私钥,因此尝试将加密方式篡改为HS256,即可使用公钥进行jwt数据篡改。
本题使用nodejs,在public.key的当前目录下新建js文件
1 | const jwt = require('jsonwebtoken'); |
终端运行node jwt.js 得到token,再重新发包得到flag
参考:
https://www.cnblogs.com/meng-han/p/16867619.html
https://blog.csdn.net/q20010619/article/details/120420461