JWT安全:令牌伪造、篡改与防御

作者:Yolo 发布时间: 2026-05-30 阅读量:3

JWT安全:令牌伪造、篡改与防御

什么是JWT

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为JSON对象。JWT由三部分组成:Header、Payload和Signature,通过.连接。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

JWT结构解析

部分内容说明
Header{"alg":"HS256","typ":"JWT"}算法和类型
Payload{"sub":"123","name":"John"}声明数据
SignatureHMAC-SHA256签名验证完整性

JWT安全威胁

1. 算法混淆攻击(Algorithm Confusion)

攻击原理: 将签名算法从非对称(RS256)改为对称(HS256),用公钥作为HMAC密钥验证。

# 攻击示例:伪造JWT
import jwt

# 获取服务器的公钥
public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----"""

# 伪造Token,使用HS256和公钥作为密钥
fake_token = jwt.encode(
{"user": "admin", "role": "admin"},
key=public_key,
algorithm="HS256"
)

防御:

# 严格验证算法
import jwt

def verify_token(token, public_key):
try:
payload = jwt.decode(
token,
public_key,
algorithms=["RS256"],
options={"require": ["exp", "iss", "sub"]}
)
return payload
except jwt.InvalidTokenError:
return None

2. 密钥暴力破解

攻击原理: 使用弱密钥或密钥泄露导致HMAC签名可被破解。

# 使用jwt_tool进行密钥爆破
python3 jwt_tool.py eyJhbGciOiJIUzI1NiIs... -C -d /usr/share/wordlists/rockyou.txt

防御:

  • 使用至少256位的强密钥
  • 定期轮换密钥
  • 使用密钥管理系统(KMS)

import secrets

# 生成安全的随机密钥
secure_key = secrets.token_urlsafe(32)

3. Token篡改(None Algorithm)

攻击原理: 将算法改为none,绕过签名验证。

{"alg":"none","typ":"JWT"}

防御:

def verify_token_strict(token, secret):
try:
payload = jwt.decode(
token,
secret,
algorithms=["HS256"],
options={
"verify_signature": True,
"require": ["exp"]
}
)
return payload
except jwt.InvalidTokenError:
return None

4. 过期时间绕过

攻击原理: 修改Payload中的exp(过期时间)字段。

import base64
import json

def decode_without_verify(token):
parts = token.split('.')
payload = base64.urlsafe_b64decode(parts[1] + '==')
return json.loads(payload)

payload = decode_without_verify(original_token)
payload['exp'] = 9999999999

防御:

import time

def verify_expiration(payload):
exp = payload.get('exp')
if not exp:
return False
if exp < time.time():
return False
max_future = time.time() + 86400 * 30
if exp > max_future:
return False
return True

5. 密钥泄露利用

场景: 密钥硬编码在代码中,通过Git泄露或反编译获取。

# 危险的硬编码密钥
SECRET_KEY = "my-secret-key-123"

防御:

import os

SECRET_KEY = os.environ.get('JWT_SECRET_KEY')
if not SECRET_KEY:
raise ValueError("JWT_SECRET_KEY not set")

JWT安全最佳实践

1. 算法白名单

ALLOWED_ALGORITHMS = ['HS256', 'RS256', 'ES256']

def verify_token(token, key):
try:
payload = jwt.decode(
token, key,
algorithms=ALLOWED_ALGORITHMS,
options={"verify_aud": True}
)
return payload
except jwt.InvalidAlgorithmError:
raise ValueError("不支持的算法")
except jwt.ExpiredSignatureError:
raise ValueError("Token已过期")
except jwt.InvalidTokenError:
raise ValueError("无效的Token")

2. 完整的验证流程

def comprehensive_verify(token, secret, expected_issuer, expected_audience):
try:
payload = jwt.decode(
token,
secret,
algorithms=['HS256'],
issuer=expected_issuer,
audience=expected_audience,
options={
'verify_exp': True,
'verify_iat': True,
'verify_nbf': True,
'verify_iss': True,
'verify_aud': True,
'require': ['exp', 'iat', 'iss', 'aud']
}
)
if payload.get('jti'):
if is_token_revoked(payload['jti']):
raise ValueError("Token已被撤销")
return payload
except jwt.ExpiredSignatureError:
raise ValueError("Token已过期")
except jwt.InvalidIssuerError:
raise ValueError("无效的签发者")
except jwt.InvalidAudienceError:
raise ValueError("无效的受众")
except jwt.InvalidTokenError as e:
raise ValueError(f"Token验证失败: {str(e)}")

3. 安全存储密钥

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend

private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)

encrypted_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(b'my-password')
)

4. Token生命周期管理

class TokenManager:
def __init__(self):
self.revoked_tokens = set()
self.refresh_tokens = {}

def create_token_pair(self, user_id):
access_token = jwt.encode(
{
'user_id': user_id,
'type': 'access',
'exp': datetime.utcnow() + timedelta(minutes=15),
'iat': datetime.utcnow(),
'jti': secrets.token_urlsafe(16)
},
ACCESS_SECRET,
algorithm='HS256'
)

refresh_token = jwt.encode(
{
'user_id': user_id,
'type': 'refresh',
'exp': datetime.utcnow() + timedelta(days=7),
'iat': datetime.utcnow(),
'jti': secrets.token_urlsafe(16)
},
REFRESH_SECRET,
algorithm='HS256'
)

self.refresh_tokens[refresh_token] = user_id
return access_token, refresh_token

def revoke_token(self, token_id):
self.revoked_tokens.add(token_id)

def is_revoked(self, token_id):
return token_id in self.revoked_tokens

常见漏洞利用工具

jwt_tool

# 安装
pip3 install jwt-tool

# 基本使用
jwt_tool.py eyJhbGciOiJIUzI1NiIs... -t

# 密钥爆破
jwt_tool.py token.txt -C -d wordlist.txt

# 算法混淆测试
jwt_tool.py token.txt -X a

在线工具

防御总结

威胁防御措施
算法混淆严格算法白名单
密钥破解强密钥 + 定期轮换
None算法拒绝none算法
过期绕过服务端验证时间
密钥泄露环境变量/KMS存储
重放攻击使用JTI + Token黑名单
Token窃取短期Token + HTTPS

JWT安全的核心在于:不要信任客户端,服务端必须严格验证每一个Token的签名、过期时间和声明内容。 任何验证疏忽都可能导致认证绕过或权限提升。