深入了解Json Web Token之实战篇
字数 2714 2025-08-18 11:37:33

JSON Web Token (JWT) 安全攻防实战指南

1. JWT 基础概念回顾

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

  • Header (头部)
  • Payload (负载)
  • Signature (签名)

格式为:header.payload.signature

2. JWT 攻击手段详解

2.1 敏感信息泄露

攻击原理:当服务端的秘钥泄密时,JWT 的伪造变得非常简单。

防御措施

  • 妥善保管私钥
  • 使用密钥管理系统
  • 定期轮换密钥

2.2 将加密方式改为'none'

攻击原理

  • 将 alg 字段更改为 none
  • 删除签名数据,仅保留 header.payload.
  • 某些 JWT 库支持无算法验证

防御措施

  • 禁用 none 算法
  • 将开启 alg:none 作为额外配置选项
  • 强制验证签名

实战案例:Juice Shop JWT issue 1

  1. 获取正常 JWT 令牌
  2. 修改头部为 {"alg":"none","typ":"JWT"}
  3. 删除签名部分
  4. 提交修改后的令牌

2.3 将算法 RS256 修改为 HS256

攻击原理

  • RS256 使用非对称加密(私钥签名,公钥验证)
  • HS256 使用对称加密(同一密钥签名和验证)
  • 攻击者获取公钥后,可修改算法为 HS256 并用公钥签名

防御措施

  • 禁止 HS256 等对称加密算法读取公钥
  • 将秘钥与验证算法严格匹配
  • 检查密钥类型与算法是否匹配

2.4 HS256 密钥破解

攻击原理:当 HS256 密钥强度较弱时,可直接暴力破解。

防御措施

  • 使用足够复杂(长且随机)的密钥
  • 定期更换密钥
  • 使用密钥派生函数增强密钥强度

实战工具

  • c-jwt-cracker:专门用于爆破 JWT HS256 密钥的工具

2.5 错误的堆叠加密+签名验证假设

2.5.1 错误的堆叠加密

攻击原理

  • 修改 JWE (JSON Web Encryption) 的 ciphertext
  • 即使解密失败,部分库仍会输出部分解密结果
  • 可能获得修改后的特权字段

防御措施

  • 解密所有数据,而非提取单个字段
  • 使用附加认证数据 (ADD)
  • 严格验证解密完整性

2.5.2 签名假设验证

攻击原理

  • 嵌套 JWS (JSON Web Signature) 中,仅验证外层签名
  • 内层 payload 可被篡改

防御措施

  • 验证所有层面的签名
  • 禁止不必要的数据嵌套

2.6 无效椭圆曲线攻击

攻击原理

  • 利用椭圆曲线加密中未验证输入参数的漏洞
  • 通过精心设计的输入恢复私钥

防御措施

  • 验证所有输入参数的有效性
  • 检查公钥是否为有效椭圆曲线点
  • 验证私钥在有效值范围内

2.7 替换攻击

2.7.1 不同接收方攻击

攻击原理

  • 同一认证机构为多个应用签发 JWT
  • 攻击者用 App1 的令牌访问 App2

防御措施

  • 使用 aud (Audience) 声明限制令牌使用范围
  • "aud": "App1"

2.7.2 相同接收方攻击/跨越式 JWT

攻击原理

  • 同一站点下多个应用使用相同密钥
  • 部分应用未验证 aud 声明
  • 攻击者用受限应用的令牌访问未验证应用

防御措施

  • 所有子应用强制验证 aud 声明
  • 为不同应用使用不同密钥

2.8 JWT + SQL 注入

攻击原理

  • 通过 kid (Key ID) 参数确定使用哪个密钥
  • 当 kid 通过数据库查询获取时,可能引入 SQL 注入
  • 注入恶意查询控制返回的密钥内容

防御措施

  • 对 kid 参数严格过滤
  • 使用参数化查询访问数据库
  • 限制数据库账户权限

3. 实战练习详解

3.1 敏感信息泄露实战

环境:http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php

步骤

  1. 获取公钥/私钥:

    • http://demo.sjoerdlangkemper.nl/jwtdemo/private.pem
    • http://demo.sjoerdlangkemper.nl/jwtdemo/public.pem
  2. 使用私钥生成新令牌:

$keychain = new Keychain();
$sign = new Sha256();
$token = "eyJ0eXAiO...";
$token = (new Parser())->parse((string) $token);
$hacktoken = (new Builder())
    ->setIssuer($token->getClaim('iss'))
    ->setIssuedAt($token->getClaim('iat'))
    ->setExpiration($token->getClaim('exp'))
    ->set("data",["hack"=>"shaobaobaoer"])
    ->sign($sign,$keychain->getPrivateKey('file://key_box/private.pem'))
    ->getToken();
echo $hacktoken.PHP_EOL;
var_dump($hacktoken->verify($sign,$keychain->getPublicKey('file://key_box/public.pem')));

3.2 Juice Shop JWT issue 1

目标:伪造无签名 JWT 令牌,冒充用户 jwtn3d@juice-sh.op

步骤

  1. 获取正常 JWT 令牌
  2. 修改头部为 {"alg":"none","typ":"JWT"}
  3. 修改 payload 中的 email 字段
  4. 删除签名部分,格式为 header.payload.
  5. 提交修改后的令牌

3.3 加密方式更改实战

原理:将 RS256 改为 HS256,用公钥作为 HMAC 密钥

示例代码

$secret = file_get_contents("./key_box/public.pem");
$sign = new Sha256();
$token = "eyJ0eXAiO...";
$token = (new Parser())->parse((string) $token);
$hacktoken = (new Builder())
    ->setIssuer($token->getClaim('iss'))
    ->setIssuedAt($token->getClaim('iat'))
    ->setExpiration($token->getClaim('exp'))
    ->set("data",["hack"=>"shaobaobaoer"])
    ->sign($sign,$secret)
    ->getToken();
echo $hacktoken.PHP_EOL;
var_dump($hacktoken->verify($sign,$secret));

3.4 HMAC 秘钥爆破实战

工具:c-jwt-cracker

步骤

  1. 获取 JWT 令牌,如:
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ImZhbHNlIn0.oe4qhTxvJB8nNAsFWJc7_m3UylVZzO3FwhkYuESAyUM
  2. 使用工具爆破密钥:
    ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ImZhbHNlIn0.oe4qhTxvJB8nNAsFWJc7_m3UylVZzO3FwhkYuESAyUM
    
  3. 获取密钥后(如"54l7y"),使用正确密钥生成新令牌

4. 防御最佳实践

  1. 算法处理

    • 明确指定允许的算法
    • 禁止 none 算法
    • 区分对称和非对称密钥使用场景
  2. 密钥管理

    • 使用足够强度的密钥
    • 定期轮换密钥
    • 安全存储私钥
  3. 声明验证

    • 验证 iss (Issuer)、aud (Audience) 等标准声明
    • 验证 exp (Expiration Time)、nbf (Not Before) 等时间声明
    • 自定义声明也需验证
  4. 库选择

    • 选择维护良好、安全记录良好的库
    • 定期更新库版本
    • 评估库的安全特性
  5. 其他措施

    • 使用 HTTPS 传输 JWT
    • 考虑短期有效的令牌
    • 实现令牌撤销机制

5. 推荐的 JWT 库

PHP 库评测:

  1. firebase/php-jwt (★3786)

    • 支持 PHP5/7
    • 操作简单但功能有限
  2. lcobucci/jwt (★2729)

    • 支持 PHP5/7
    • 不支持 JWE
    • 操作简单
  3. spomky-labs/jose (★351)

    • 仅支持 PHP7
    • 功能齐全,支持多重 JWE/JWS 及序列化

6. 参考资料

  1. JWT 官方手册
  2. JWT 库漏洞报告
  3. 无效曲线攻击文档

通过理解这些攻击手段和防御措施,开发人员可以更安全地实现 JWT,安全研究人员也可以更有效地测试 JWT 实现的安全性。

JSON Web Token (JWT) 安全攻防实战指南 1. JWT 基础概念回顾 JSON Web Token (JWT) 是一种开放标准 (RFC 7519),用于在各方之间安全地传输信息作为 JSON 对象。JWT 通常由三部分组成: Header (头部) Payload (负载) Signature (签名) 格式为: header.payload.signature 2. JWT 攻击手段详解 2.1 敏感信息泄露 攻击原理 :当服务端的秘钥泄密时,JWT 的伪造变得非常简单。 防御措施 : 妥善保管私钥 使用密钥管理系统 定期轮换密钥 2.2 将加密方式改为'none' 攻击原理 : 将 alg 字段更改为 none 删除签名数据,仅保留 header.payload. 某些 JWT 库支持无算法验证 防御措施 : 禁用 none 算法 将开启 alg:none 作为额外配置选项 强制验证签名 实战案例 :Juice Shop JWT issue 1 获取正常 JWT 令牌 修改头部为 {"alg":"none","typ":"JWT"} 删除签名部分 提交修改后的令牌 2.3 将算法 RS256 修改为 HS256 攻击原理 : RS256 使用非对称加密(私钥签名,公钥验证) HS256 使用对称加密(同一密钥签名和验证) 攻击者获取公钥后,可修改算法为 HS256 并用公钥签名 防御措施 : 禁止 HS256 等对称加密算法读取公钥 将秘钥与验证算法严格匹配 检查密钥类型与算法是否匹配 2.4 HS256 密钥破解 攻击原理 :当 HS256 密钥强度较弱时,可直接暴力破解。 防御措施 : 使用足够复杂(长且随机)的密钥 定期更换密钥 使用密钥派生函数增强密钥强度 实战工具 : c-jwt-cracker:专门用于爆破 JWT HS256 密钥的工具 2.5 错误的堆叠加密+签名验证假设 2.5.1 错误的堆叠加密 攻击原理 : 修改 JWE (JSON Web Encryption) 的 ciphertext 即使解密失败,部分库仍会输出部分解密结果 可能获得修改后的特权字段 防御措施 : 解密所有数据,而非提取单个字段 使用附加认证数据 (ADD) 严格验证解密完整性 2.5.2 签名假设验证 攻击原理 : 嵌套 JWS (JSON Web Signature) 中,仅验证外层签名 内层 payload 可被篡改 防御措施 : 验证所有层面的签名 禁止不必要的数据嵌套 2.6 无效椭圆曲线攻击 攻击原理 : 利用椭圆曲线加密中未验证输入参数的漏洞 通过精心设计的输入恢复私钥 防御措施 : 验证所有输入参数的有效性 检查公钥是否为有效椭圆曲线点 验证私钥在有效值范围内 2.7 替换攻击 2.7.1 不同接收方攻击 攻击原理 : 同一认证机构为多个应用签发 JWT 攻击者用 App1 的令牌访问 App2 防御措施 : 使用 aud (Audience) 声明限制令牌使用范围 如 "aud": "App1" 2.7.2 相同接收方攻击/跨越式 JWT 攻击原理 : 同一站点下多个应用使用相同密钥 部分应用未验证 aud 声明 攻击者用受限应用的令牌访问未验证应用 防御措施 : 所有子应用强制验证 aud 声明 为不同应用使用不同密钥 2.8 JWT + SQL 注入 攻击原理 : 通过 kid (Key ID) 参数确定使用哪个密钥 当 kid 通过数据库查询获取时,可能引入 SQL 注入 注入恶意查询控制返回的密钥内容 防御措施 : 对 kid 参数严格过滤 使用参数化查询访问数据库 限制数据库账户权限 3. 实战练习详解 3.1 敏感信息泄露实战 环境 :http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php 步骤 : 获取公钥/私钥: http://demo.sjoerdlangkemper.nl/jwtdemo/private.pem http://demo.sjoerdlangkemper.nl/jwtdemo/public.pem 使用私钥生成新令牌: 3.2 Juice Shop JWT issue 1 目标 :伪造无签名 JWT 令牌,冒充用户 jwtn3d@juice-sh.op 步骤 : 获取正常 JWT 令牌 修改头部为 {"alg":"none","typ":"JWT"} 修改 payload 中的 email 字段 删除签名部分,格式为 header.payload. 提交修改后的令牌 3.3 加密方式更改实战 原理 :将 RS256 改为 HS256,用公钥作为 HMAC 密钥 示例代码 : 3.4 HMAC 秘钥爆破实战 工具 :c-jwt-cracker 步骤 : 获取 JWT 令牌,如: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ImZhbHNlIn0.oe4qhTxvJB8nNAsFWJc7_m3UylVZzO3FwhkYuESAyUM 使用工具爆破密钥: 获取密钥后(如"54l7y"),使用正确密钥生成新令牌 4. 防御最佳实践 算法处理 : 明确指定允许的算法 禁止 none 算法 区分对称和非对称密钥使用场景 密钥管理 : 使用足够强度的密钥 定期轮换密钥 安全存储私钥 声明验证 : 验证 iss (Issuer)、aud (Audience) 等标准声明 验证 exp (Expiration Time)、nbf (Not Before) 等时间声明 自定义声明也需验证 库选择 : 选择维护良好、安全记录良好的库 定期更新库版本 评估库的安全特性 其他措施 : 使用 HTTPS 传输 JWT 考虑短期有效的令牌 实现令牌撤销机制 5. 推荐的 JWT 库 PHP 库评测: firebase/php-jwt (★3786) 支持 PHP5/7 操作简单但功能有限 lcobucci/jwt (★2729) 支持 PHP5/7 不支持 JWE 操作简单 spomky-labs/jose (★351) 仅支持 PHP7 功能齐全,支持多重 JWE/JWS 及序列化 6. 参考资料 JWT 官方手册 JWT 库漏洞报告 无效曲线攻击文档 通过理解这些攻击手段和防御措施,开发人员可以更安全地实现 JWT,安全研究人员也可以更有效地测试 JWT 实现的安全性。