【Web安全】JWT常见安全漏洞总结

文章目录

  • 前言
  • [1. JWT基础与漏洞概述](#1. JWT基础与漏洞概述)
  • [2. JWT核心漏洞解析](#2. JWT核心漏洞解析)
    • [2.1 未校验签名](#2.1 未校验签名)
      • [2.1.1 漏洞原理](#2.1.1 漏洞原理)
      • [2.1.2 利用方式](#2.1.2 利用方式)
      • [2.1.3 实战脚本](#2.1.3 实战脚本)
    • [2.2 算法篡改漏洞](#2.2 算法篡改漏洞)
      • [2.2.1 漏洞原理](#2.2.1 漏洞原理)
      • [2.2.2 核心说明](#2.2.2 核心说明)
      • [2.2.3 攻击流程](#2.2.3 攻击流程)
    • [2.3 弱密钥漏洞](#2.3 弱密钥漏洞)
      • [2.3.1 漏洞原理](#2.3.1 漏洞原理)
      • [2.3.2 利用方式](#2.3.2 利用方式)
    • [2.4 垂直越权](#2.4 垂直越权)
      • [2.4.1 漏洞原理](#2.4.1 漏洞原理)
      • [2.4.2 利用流程](#2.4.2 利用流程)
    • [2.5 KID字段注入](#2.5 KID字段注入)
      • [2.5.1 触发条件](#2.5.1 触发条件)
      • [2.5.2 四类利用方式](#2.5.2 四类利用方式)
  • [3. 漏洞防御建议](#3. 漏洞防御建议)
  • [4. 总结](#4. 总结)

⚠️本博文所涉安全渗透测试技术、方法及案例,仅用于网络安全技术研究与合规性交流,旨在提升读者的安全防护意识与技术能力。任何个人或组织在使用相关内容前,必须获得目标网络 / 系统所有者的明确且书面授权,严禁用于未经授权的网络探测、漏洞利用、数据获取等非法行为。

前言

在当今的Web开发中,JSON Web Token(JWT)作为身份认证与授权的常用凭证,广泛应用于前后端分离、微服务等架构。然而,由于服务端配置不当、算法使用不规范等原因,JWT容易出现多种漏洞,被攻击者利用来实现越权访问或伪造身份。

1. JWT基础与漏洞概述

JWT由Header(头部)、Payload(载荷)、Signature(签名)三部分构成,主要用于实现无状态的身份验证。正常情况下,服务端通过校验签名来确认JWT的完整性与合法性。但如果校验逻辑存在缺陷,攻击者就能够通过篡改凭证、破解密钥等手段绕过认证,获取未授权的访问权限。

2. JWT核心漏洞解析

2.1 未校验签名

2.1.1 漏洞原理

服务端存在两种致命缺陷:一是完全不校验JWT的签名部分,直接信任Payload中的内容;二是允许使用alg: none无签名算法,该算法规定JWT无需进行签名校验,仅需保证格式正确即可通过验证。这两种情况均允许攻击者任意篡改Payload中的用户ID、权限等核心信息,实现身份伪造。

2.1.2 利用方式

  1. 修改JWT头部(Header),将算法指定为none,即"alg": "none"
  2. 篡改Payload中的关键字段,如将普通用户ID(sub: "10086")改为管理员ID(sub: "1"),调整过期时间(exp)延长凭证有效期;
  3. 清除签名部分(JWT最后一个.后面的内容留空),提交篡改后的JWT即可绕过认证。

2.1.3 实战脚本

以下Python脚本可直接构造None算法的恶意JWT,可根据目标系统调整Payload字段:

python 复制代码
import time
import jwt


def forge_jwt_none_attack(exp_offset=3600):
    """
    构造 JWT None 算法攻击的 Token
    :param exp_offset: 过期时间偏移(秒),默认1小时
    :return: 构造好的 JWT Token
    """
    header = {
        "typ": "JWT",
        "alg": "none"
    }

    # Payload
    now = int(time.time())
    payload = {
        "exp": now + exp_offset,  # 过期时间
        "iat": now,  # 签发时间
        "iss": "echisan",
        "sub": "业务参数",
    }

    # 生成 JWT:key=None, algorithm=None
    try:
        jwt_token = jwt.encode(
            payload,
            key=None,
            algorithm=None,
            headers=header
        )
    except TypeError:
        jwt_token = jwt.encode(
            payload,
            key="",  # 部分旧版本需要传空字符串
            algorithm="none",
            headers=header
        )

    # 处理编码
    if isinstance(jwt_token, bytes):
        jwt_token = jwt_token.decode("utf-8")

    return jwt_token


if __name__ == "__main__":
    forged_token = forge_jwt_none_attack()
    print(forged_token)

2.2 算法篡改漏洞

2.2.1 漏洞原理

正常业务使用RS256非对称算法签名,服务器持有私钥进行签名,并对外公开公钥用于验签。该漏洞的根源在于服务端不硬编码指定验签算法,而是直接读取JWT头部的alg字段来动态选择验签方式。攻击者将头部的alg:RS256篡改为alg:HS256,然后利用服务器公开的RSA公钥直接作为HS256的对称密钥,自行完成签名伪造。服务端读取alg为HS256后,会误用公钥当作对称密钥完成验签,从而直接放行恶意Token。

2.2.2 核心说明

  1. 服务器拥有私钥,为何不用私钥验签?
    RS256规范规定只能用公钥验签,私钥仅负责签名,验签流程全程不会使用私钥,这是协议的固有规则。
  2. 为何会用公钥当做HS256密钥?
    这是由于程序逻辑存在缺陷:只判断alg字段,不设置算法白名单进行拦截。当切换为HS256对称验签后,直接复用原有传入的公钥作为对称密钥,导致验签失效。

2.2.3 攻击流程

  1. 抓取正常业务JWT,获取服务器对外暴露的RSA公钥;
  2. 修改Header内alg值,由RS256改为HS256;
  3. 篡改Payload内用户ID、权限、角色等敏感字段;
  4. 使用服务器公钥作为HS256密钥重新生成签名;
  5. 携带伪造Token请求接口,服务端成功验签通过,实现身份伪造。

2.3 弱密钥漏洞

2.3.1 漏洞原理

JWT使用对称加密算法(如HS256)时,服务端会使用固定密钥对JWT进行签名与校验。若该密钥强度极低,攻击者可通过暴力破解的方式获取密钥,进而伪造任意合法JWT。

2.3.2 利用方式

核心是通过工具爆破弱密钥,常用工具推荐:TscanPlus(TideSec开源工具):集成JWT弱密钥破解功能,支持自定义字典,操作便捷,可直接联动其他功能进行后续攻击;破解密钥后,即可使用该密钥签名任意篡改后的Payload,生成合法JWT。

2.4 垂直越权

2.4.1 漏洞原理

垂直越权并非JWT自身的算法漏洞,而是基于上述两种漏洞(未校验签名、弱密钥)的衍生攻击。攻击者通过伪造高权限用户的JWT凭证,绕过服务端的权限控制,访问原本只有管理员等高级角色才能访问的接口或资源。

2.4.2 利用流程

  1. 通过无签名攻击或弱密钥爆破,获取伪造高权限JWT的能力;
  2. 篡改Payload中的权限字段(如role: "admin"),生成高权限JWT;
  3. 携带该JWT请求高权限接口(如/admin/user/list/system/setting),实现垂直越权访问。

2.5 KID字段注入

2.5.1 触发条件

JWT头部的kid(Key ID)字段用于指定服务端校验签名时使用的密钥(如密钥文件路径、数据库中的密钥ID)。若服务端未对kid字段进行过滤,直接将其拼接至密钥读取、查询逻辑中,攻击者可通过注入恶意内容,实现SQL注入、命令执行、文件读取等攻击。

2.5.2 四类利用方式

  1. SQL注入
    核心思路:通过kid字段注入SQL语句,篡改密钥查询结果,让服务端使用攻击者指定的密钥进行签名校验。示例注入语句:xxx_key' UNION select'mykey' from INFORMATION_SCHEMA.SYSTEM_USERS --,关键注意点:xxx_key必须是不存在的密钥(确保UNION查询生效);mykey为攻击者指定的密钥,可根据需求进行Base64编码,增强隐蔽性。此外,还可结合布尔盲注、时间盲注,获取服务端数据库中的真实密钥。
  2. 命令注入
    适用场景:服务端使用Ruby等语言,通过open函数读取密钥文件时,kid字段可拼接命令。测试方式:在kid字段中注入命令拼接内容,如kid: "key|whoami",若服务端执行该命令,可获取服务器权限。该场景较为少见,主要出现在配置不规范的Ruby项目中。
  3. 文件读取
  • 路径穿越读取密钥 :通过kid字段注入路径穿越字符,读取服务端本地的密钥文件,如kid: "../../../../../etc/passwd"(读取系统用户信息)、kid: "../../../../../var/www/secret.key"(读取应用密钥文件);
  • 空密钥利用 :注入kid: "../../../../../dev/null",让服务端读取空文件作为密钥,此时可使用空密钥签名JWT,实现伪造。

3. 漏洞防御建议

针对上述漏洞,从开发与运维角度给出以下防御措施,避免JWT被滥用:

  1. 严格校验签名:禁止使用alg: none算法,服务端必须校验JWT的签名完整性,不信任未签名或签名无效的凭证;明确指定验签算法,避免动态读取alg字段导致算法篡改漏洞。
  2. 强化密钥安全:使用对称加密算法时,采用高强度密钥(至少16位随机字符串),定期更换密钥;优先使用非对称加密算法(如RS256),私钥严格保管,不对外泄露。
  3. 过滤危险字段:对JWT头部的kid等字段进行严格过滤,禁止特殊字符(如'"|../),避免注入攻击。
  4. 限制Payload权限:Payload中不存储敏感信息(如密码、密钥),权限字段(如role)需在服务端二次校验,不依赖JWT中的内容。
  5. 缩短凭证有效期:合理设置JWT的exp(过期时间),建议不超过1小时,降低凭证泄露后的风险。

4. 总结

JWT漏洞的产生主要源于服务端校验逻辑不严谨、配置不当。攻击者利用篡改凭证、破解密钥、注入攻击等手段,绕过身份认证与权限控制。

对于安全从业者,可借助本文内容快速识别JWT漏洞,开展渗透测试。后续可结合具体项目场景,深入研究JWT的进阶攻击方式,进一步提升安全防护能力。

本文是「Web安全基础」系列内容,点击专栏导航查看全部系列内容。

相关推荐
风途科技~2 小时前
山体边坡安全如何守护?地表裂缝监测站实时掌握形变动态
人工智能·安全
网安小学生(兼顾数据库版)2 小时前
主流SBOM生成工具横评:自动化、准确性与合规支持
网络·安全·自动化
@insist1233 小时前
信息安全工程师-网站安全顶层认知:威胁、需求与防护体系框架
网络·安全·web安全
@insist1233 小时前
信息安全工程师-Apache/IIS安全增强与OWASP漏洞防护
安全·apache·软考·信息安全工程师·软件水平考试
山川绿水11 小时前
bugku——PWN——overflow2
人工智能·web安全·网络安全
chipsense13 小时前
【安全警示】充电桩漏电保护正在被忽视:为什么B型剩余电流检测是强制刚需
安全·充电桩·漏电流检测
上海云盾-小余14 小时前
内网边界安全管控:访问权限隔离与入侵阻断方案
网络·安全·web安全
许彰午14 小时前
加密解密加签验签——接口安全的最后一道防线
安全
智慧医养结合软件开源15 小时前
智慧养老系统医生管理模块:专业赋能,筑牢老人诊疗安全防线
大数据·人工智能·安全·生活