Skip to content

[Vulnerability] 存在可能导致越权风险的硬编码JWT Secret #164

Description

@lx915

描述:

本项目是一个开源项目,任何用户都能获取到该项目中的硬编码的JWT Secret。同时,使用JWT Secret默认值启动项目时并没有任何警告提示,所以大多数用户可能不会修改此JWT Secret默认值,这可能导致攻击者伪造任意用户的权限令牌,从而绕过认证与授权机制,访问受保护接口。

密钥位置:

token.secretKey=abcdefghijklmnopqrstuvwxyz

漏洞类型:

类型 说明
CWE-798 Use of Hard-coded Credentials
CWE-321 Use of Hard-coded Cryptographic Key

风险等级:

High/Critical

可利用分析:

1. 密钥加载链路

src/main/java/top/naccl/util/JwtUtils.java 第 24 行通过 @Value("${token.secretKey}") 从配置文件加载 JWT Secret。该值定义于 src/main/resources/application-dev.properties 第 34 行,值为 abcdefghijklmnopqrstuvwxyz,属于非空、非 null、可静态确定的硬编码密钥。

同时,application.properties 第 1 行设置 spring.profiles.active=dev,因此默认部署时会加载 dev 配置,使该硬编码 Secret 进入默认运行环境。

阶段 位置 说明
Profile 配置 application.properties:1 默认启用 dev Profile
Secret 定义 application-dev.properties:34 token.secretKey 被硬编码为 abcdefghijklmnopqrstuvwxyz
Secret 注入 JwtUtils.java:24 通过 @Value("${token.secretKey}") 注入
Token 签发 JwtUtils 相关方法 使用该 Secret 生成 JWT
Token 校验 JwtUtils.getTokenBody 使用该 Secret 校验 JWT 签名和过期时间

2. JWT Payload 分析

项目中存在多类 Token 生成逻辑,Payload 字段如下:

生成位置 Payload 字段 安全分析
JwtLoginFilter.successfulAuthentication subauthoritiesexp sub 为用户名,属于可枚举身份标识;authorities 为角色字符串,可被攻击者伪造
LoginController.login subexp sub 格式为 admin: + 用户名,属于可伪造身份标识
BlogController.checkBlogPassword subexp sub 为博客 ID 字符串,通常为低熵整数或可枚举业务标识

字段安全属性如下:

字段 含义 安全分析
sub 用户名或博客 ID 持久化标识或低熵业务标识,攻击者可获取、枚举或伪造
authorities 角色字符串,如 ROLE_admin, 权限字段,攻击者可直接伪造为管理员角色
exp 过期时间 时间字段,攻击者可设置为未来时间

Payload 中不存在服务端生成并强制校验的随机高熵字段,也未绑定服务端会话状态、jtinonce 或 Token 版本号。

3. Token 校验链路

JwtFilter 拦截所有 /admin/** 请求,并执行以下流程:

  1. Authorization Header 中获取 JWT;
  2. 调用 JwtUtils.getTokenBody 解析 Token;
  3. 仅校验 JWT 签名和过期时间;
  4. 从 Payload 中直接提取 subjectauthorities
  5. 使用这些字段构造 UsernamePasswordAuthenticationToken
  6. 将认证对象写入 SecurityContextHolder
  7. 后续由 Spring Security 基于该认证上下文执行角色判断。

SecurityConfig 中的访问控制规则包括:

路由 权限要求
GET /admin/** hasAnyRole("admin", "visitor")
其他 /admin/** hasRole("admin")

由于角色权限直接来自 JWT Payload 中的 authorities 字段,攻击者在掌握硬编码 Secret 后,可以自行构造包含管理员权限的 Token。

4. Token 状态性

该 Token 校验机制属于无状态 Token 模型。服务端仅依赖签名密钥和过期时间判断 Token 是否有效,不进行以下校验:

  • 不回查数据库确认用户是否存在;
  • 不检查服务端会话状态;
  • 不检查 Token 撤销列表;
  • 不验证随机 jtinonce
  • 不校验任何攻击者不可伪造的服务端字段。

5. 业务影响链路

JwtFilter 会将 JWT Payload 中的 subjectauthorities 直接作为身份与权限依据写入 Spring Security 上下文。后续管理端控制器会信任该认证上下文执行敏感操作,例如:

  • 博客管理;
  • 评论管理;
  • 站点设置;
  • 账号管理;
  • 密码修改;
  • 其他 /admin/** 受保护接口操作。

这些业务逻辑不额外回查用户存在性或权限来源,因此伪造的管理员角色可直接生效。

6. 攻击结论

攻击者一旦获取硬编码 Secret abcdefghijklmnopqrstuvwxyz,即可伪造任意 JWT,例如:

  • 设置 sub 为任意用户名;
  • 设置 authoritiesROLE_admin,
  • 设置 exp 为未来时间。

该伪造 Token 可通过 JwtFilter 的签名校验,并被 Spring Security 识别为管理员身份。攻击者随后可访问所有 /admin/** 端点,执行博客管理、评论管理、站点设置、账号密码修改等敏感操作。

影响:

  • 攻击者可伪造任意用户的 JWT
  • 可冒充管理员或高权限账号访问敏感接口
  • 用户身份认证机制失效
  • 可能导致数据泄露、越权操作或账户接管

修复建议:

可以将JWT Secret放入系统环境变量中或者禁止使用默认值启动项目。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions