JWT安全漏洞之密钥混淆攻击(Key Confusion Attack)详解
字数 3334 2025-12-08 22:30:24

JWT安全漏洞之密钥混淆攻击(Key Confusion Attack)详解

一、 题目/知识点描述

密钥混淆攻击(Key Confusion Attack),也被称为算法混淆攻击(Algorithm Confusion Attack),是针对JSON Web Token的一种特定安全漏洞。它利用了JWT验证库在处理不同类型密钥(对称加密密钥与非对称加密公钥/私钥)时可能存在的逻辑缺陷。当攻击者能够获取或推测出用于验证JWT签名的公钥时,他们可以构造一个使用对称加密算法(如HS256)签名的恶意Token,但欺骗验证方使用先前获取的非对称加密算法的公钥(如RSA的公钥)作为对称密钥来进行签名验证,从而绕过签名检查,伪造任意内容的JWT。这种攻击在JWT实现不当的应用程序中可能导致身份验证绕过、权限提升等严重后果。

二、 解题过程循序渐进讲解

步骤1:回顾JWT的基本结构与签名机制
首先,我们需要明确JWT通常由三部分组成:头部(Header)、载荷(Payload)和签名(Signature),以点号分隔。

  • 头部: 声明令牌类型和签名算法。例如,{"alg": "HS256", "typ": "JWT"} 表示使用HMAC SHA256算法。
  • 载荷: 包含声明(Claims),如用户ID、过期时间等。
  • 签名: 用于验证消息在传递过程中未被篡改。签名的生成方式取决于alg字段。
    • 对于对称算法(如HS256):签名 = HMAC-SHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), 密钥)。这里的密钥是一个秘密字符串,签名和验证使用同一个密钥。
    • 对于非对称算法(如RS256):签名 = RSA-SHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), 私钥)。验证时使用对应的公钥

关键在于,验证方必须使用与签名算法alg字段匹配的密钥类型和正确的密钥值来验证签名。

步骤2:理解漏洞产生的根本原因
漏洞的核心在于JWT验证库的实现可能存在缺陷。其验证逻辑可能如下:

  1. 从JWT头部解码出alg参数(例如HS256)。
  2. 根据alg值,从应用程序配置或密钥库中获取对应的“密钥”。
  3. 使用这个“密钥”验证签名。

问题出现在第2步和第3步:

  • 密钥选择逻辑缺陷: 某些旧的或配置不当的库,可能只有一个“验证密钥”的配置项。当应用最初设计使用RS256时,这个配置项里放的是RSA公钥。但当JWT头部的alg被篡改为HS256时,验证逻辑可能错误地将这个RSA公钥直接用作HMAC算法的密钥
  • 密码学原理差异: RSA的公钥/私钥对与HMAC的共享密钥本质不同,但它们在代码中可能都以字节序列或字符串形式存在。一个有缺陷的库在收到alg=HS256的JWT时,不会判断传入的“密钥”是否真的是一个合适的HMAC密钥,而是机械地执行HMAC.verify(token, key),其中key就是那个RSA公钥。如果HMAC验证函数内部只是简单地将传入的key作为二进制密钥使用,而RSA公钥本身就是一个合法的字节序列,那么验证过程在语法上可以运行。

步骤3:攻击者利用条件分析
要成功实施密钥混淆攻击,攻击者需要满足几个条件:

  1. 获取用于验证的非对称公钥: 这是攻击的前提。公钥有时会硬编码在客户端代码(如JavaScript)、公开的API端点(如/.well-known/jwks.json)或配置文件中。如果公钥可被预测(如使用默认证书),也可能被获取。
  2. 目标应用使用有漏洞的JWT库: 应用程序使用的JWT库在处理算法和密钥匹配时存在逻辑缺陷。历史上,一些流行库的旧版本存在此问题。
  3. 应用允许或受骗使用alg: none之外的算法: 虽然alg: none攻击更简单,但已被广泛防御。密钥混淆攻击利用了从非对称算法“降级”到对称算法的过程。

步骤4:攻击步骤拆解
假设攻击场景:一个Web应用使用RS256算法签发JWT,其验证公钥(PUBLIC_KEY)是公开的或可被攻击者获取。

  1. 信息收集: 攻击者首先获取一个有效的JWT(例如通过正常登录),并从中得知应用使用的原始算法(RS256)。更重要的是,他需要通过源代码分析、网络请求探查等方式,获取到用于验证的RSA公钥(PUBLIC_KEY)。
  2. 构造恶意Token
    a. 篡改头部: 将alg字段从RS256修改为HS256
    b. 篡改载荷: 修改Payload中的声明,例如将"user": "victim"改为"user": "admin""isAdmin": true
    c. 生成签名: 这是关键一步。攻击者将PUBLIC_KEY(RSA公钥)当作HMAC-SHA256的密钥,对新的头部和载荷计算HMAC签名。即:malicious_signature = HMAC-SHA256(base64UrlEncode(modified_header) + "." + base64UrlEncode(modified_payload), PUBLIC_KEY)
    d. 组装Token: 将新的头部、载荷和生成的签名用点号连接,形成恶意JWT。
  3. 发送与验证: 攻击者将伪造的JWT放入HTTP请求的Authorization头部,发送给目标应用。
  4. 触发漏洞: 有漏洞的服务端JWT验证库接收到Token。
    • 它解码头部,看到alg: HS256
    • 它本应去获取HMAC的密钥,但由于配置或逻辑缺陷,它错误地取出了为RS256配置的RSA公钥(PUBLIC_KEY)作为“验证密钥”。
    • 它使用HS256算法,并以PUBLIC_KEY作为密钥,对接收到的头部和载荷计算HMAC值,并与Token中的签名部分进行比较。
    • 因为攻击者生成签名时使用的“密钥”(PUBLIC_KEY)和服务端用于验证的“密钥”(同一个PUBLIC_KEY)完全相同,所以HMAC验证通过。服务端错误地认为这是一个由可信方用HS256签发的有效Token,从而接受了被篡改的载荷(如提升为管理员权限)。

步骤5:防御措施详解

  1. 强制指定预期算法: 在验证JWT时,不要在代码中依赖Token头部自声明的alg值。应该在服务端验证逻辑中,显式指定预期使用的算法。例如,在使用jsonwebtoken库时,应使用jwt.verify(token, PUBLIC_KEY, { algorithms: ['RS256'] }),这样即使Token头部声明alg: HS256,库也会因为不在允许的算法列表中而拒绝验证。
  2. 密钥与算法匹配检查: 使用最新版本的、维护良好的JWT库。这些库内部会检查提供的密钥类型是否与alg参数声明的算法匹配(例如,为RS256提供公钥/私钥,为HS256提供足够长度和强度的对称密钥),从而防止密钥混淆。
  3. 密钥管理: 为不同的算法使用完全不同且无关联的密钥。避免公钥/私钥对中的公钥能作为有效的HMAC密钥字符串使用(虽然这更多是库的职责)。对于对称加密,确保使用强随机生成的、足够长的密钥。
  4. 最小化公钥暴露: 虽然公钥本身是用于公开验证的,但应避免将其存储在易被恶意利用的上下文(如客户端可直接计算的环境)。但这并非根本解决方法,根本方法在于第一条。
  5. 依赖库升级与安全审计: 定期更新JWT相关库到安全版本。检查代码中JWT验证的部分,确保没有易受攻击的模式。

总结:密钥混淆攻击是一种利用JWT验证逻辑缺陷,通过算法“降级”和密钥误用,实现签名伪造的攻击。其成功依赖公钥的获取和有漏洞的库。最有效的防御手段是在服务端验证时显式、强制地指定所接受的签名算法列表,绝不信任客户端Token中自带的alg声明。

JWT安全漏洞之密钥混淆攻击(Key Confusion Attack)详解 一、 题目/知识点描述 密钥混淆攻击(Key Confusion Attack),也被称为算法混淆攻击(Algorithm Confusion Attack),是针对JSON Web Token的一种特定安全漏洞。它利用了JWT验证库在处理不同类型密钥(对称加密密钥与非对称加密公钥/私钥)时可能存在的逻辑缺陷。当攻击者能够获取或推测出用于验证JWT签名的公钥时,他们可以构造一个使用对称加密算法(如HS256)签名的恶意Token,但欺骗验证方使用先前获取的非对称加密算法的公钥(如RSA的公钥)作为对称密钥来进行签名验证,从而绕过签名检查,伪造任意内容的JWT。这种攻击在JWT实现不当的应用程序中可能导致身份验证绕过、权限提升等严重后果。 二、 解题过程循序渐进讲解 步骤1:回顾JWT的基本结构与签名机制 首先,我们需要明确JWT通常由三部分组成:头部(Header)、载荷(Payload)和签名(Signature),以点号分隔。 头部 : 声明令牌类型和签名算法。例如, {"alg": "HS256", "typ": "JWT"} 表示使用HMAC SHA256算法。 载荷 : 包含声明(Claims),如用户ID、过期时间等。 签名 : 用于验证消息在传递过程中未被篡改。签名的生成方式取决于 alg 字段。 对于对称算法(如HS256): 签名 = HMAC-SHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), 密钥) 。这里的 密钥 是一个秘密字符串,签名和验证使用同一个密钥。 对于非对称算法(如RS256): 签名 = RSA-SHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), 私钥) 。验证时使用对应的 公钥 。 关键在于,验证方必须使用与签名算法 alg 字段匹配的密钥类型和正确的密钥值来验证签名。 步骤2:理解漏洞产生的根本原因 漏洞的核心在于JWT验证库的实现可能存在缺陷。其验证逻辑可能如下: 从JWT头部解码出 alg 参数(例如 HS256 )。 根据 alg 值,从应用程序配置或密钥库中获取对应的“密钥”。 使用这个“密钥”验证签名。 问题出现在第2步和第3步: 密钥选择逻辑缺陷 : 某些旧的或配置不当的库,可能只有一个“验证密钥”的配置项。当应用最初设计使用RS256时,这个配置项里放的是RSA公钥。但当JWT头部的 alg 被篡改为 HS256 时,验证逻辑可能错误地 将这个RSA公钥直接用作HMAC算法的密钥 。 密码学原理差异 : RSA的公钥/私钥对与HMAC的共享密钥本质不同,但它们在代码中可能都以字节序列或字符串形式存在。一个有缺陷的库在收到 alg=HS256 的JWT时,不会判断传入的“密钥”是否真的是一个合适的HMAC密钥,而是机械地执行 HMAC.verify(token, key) ,其中 key 就是那个RSA公钥。如果HMAC验证函数内部只是简单地将传入的 key 作为二进制密钥使用,而RSA公钥本身就是一个合法的字节序列,那么验证过程在语法上可以运行。 步骤3:攻击者利用条件分析 要成功实施密钥混淆攻击,攻击者需要满足几个条件: 获取用于验证的非对称公钥 : 这是攻击的前提。公钥有时会硬编码在客户端代码(如JavaScript)、公开的API端点(如 /.well-known/jwks.json )或配置文件中。如果公钥可被预测(如使用默认证书),也可能被获取。 目标应用使用有漏洞的JWT库 : 应用程序使用的JWT库在处理算法和密钥匹配时存在逻辑缺陷。历史上,一些流行库的旧版本存在此问题。 应用允许或受骗使用 alg: none 之外的算法 : 虽然 alg: none 攻击更简单,但已被广泛防御。密钥混淆攻击利用了从非对称算法“降级”到对称算法的过程。 步骤4:攻击步骤拆解 假设攻击场景:一个Web应用使用RS256算法签发JWT,其验证公钥(PUBLIC_ KEY)是公开的或可被攻击者获取。 信息收集 : 攻击者首先获取一个有效的JWT(例如通过正常登录),并从中得知应用使用的原始算法(RS256)。更重要的是,他需要通过源代码分析、网络请求探查等方式,获取到用于验证的RSA公钥(PUBLIC_ KEY)。 构造恶意Token : a. 篡改头部 : 将 alg 字段从 RS256 修改为 HS256 。 b. 篡改载荷 : 修改Payload中的声明,例如将 "user": "victim" 改为 "user": "admin" , "isAdmin": true 。 c. 生成签名 : 这是关键一步。攻击者将PUBLIC_ KEY(RSA公钥) 当作HMAC-SHA256的密钥 ,对新的头部和载荷计算HMAC签名。即: malicious_signature = HMAC-SHA256(base64UrlEncode(modified_header) + "." + base64UrlEncode(modified_payload), PUBLIC_KEY) 。 d. 组装Token : 将新的头部、载荷和生成的签名用点号连接,形成恶意JWT。 发送与验证 : 攻击者将伪造的JWT放入HTTP请求的 Authorization 头部,发送给目标应用。 触发漏洞 : 有漏洞的服务端JWT验证库接收到Token。 它解码头部,看到 alg: HS256 。 它本应去获取HMAC的密钥,但由于配置或逻辑缺陷,它 错误地 取出了为RS256配置的RSA公钥(PUBLIC_ KEY)作为“验证密钥”。 它使用 HS256 算法,并以PUBLIC_ KEY作为密钥,对接收到的头部和载荷计算HMAC值,并与Token中的签名部分进行比较。 因为攻击者生成签名时使用的“密钥”(PUBLIC_ KEY)和服务端用于验证的“密钥”(同一个PUBLIC_ KEY)完全相同,所以 HMAC验证通过 。服务端错误地认为这是一个由可信方用HS256签发的有效Token,从而接受了被篡改的载荷(如提升为管理员权限)。 步骤5:防御措施详解 强制指定预期算法 : 在验证JWT时,不要在代码中依赖Token头部自声明的 alg 值。应该在服务端验证逻辑中, 显式指定预期使用的算法 。例如,在使用 jsonwebtoken 库时,应使用 jwt.verify(token, PUBLIC_KEY, { algorithms: ['RS256'] }) ,这样即使Token头部声明 alg: HS256 ,库也会因为不在允许的算法列表中而拒绝验证。 密钥与算法匹配检查 : 使用最新版本的、维护良好的JWT库。这些库内部会检查提供的密钥类型是否与 alg 参数声明的算法匹配(例如,为RS256提供公钥/私钥,为HS256提供足够长度和强度的对称密钥),从而防止密钥混淆。 密钥管理 : 为不同的算法使用完全不同且无关联的密钥。避免公钥/私钥对中的公钥能作为有效的HMAC密钥字符串使用(虽然这更多是库的职责)。对于对称加密,确保使用强随机生成的、足够长的密钥。 最小化公钥暴露 : 虽然公钥本身是用于公开验证的,但应避免将其存储在易被恶意利用的上下文(如客户端可直接计算的环境)。但这并非根本解决方法,根本方法在于第一条。 依赖库升级与安全审计 : 定期更新JWT相关库到安全版本。检查代码中JWT验证的部分,确保没有易受攻击的模式。 总结 :密钥混淆攻击是一种利用JWT验证逻辑缺陷,通过算法“降级”和密钥误用,实现签名伪造的攻击。其成功依赖公钥的获取和有漏洞的库。最有效的防御手段是在服务端验证时 显式、强制地指定所接受的签名算法列表 ,绝不信任客户端Token中自带的 alg 声明。