描述:
本项目是一个开源项目,任何用户都能获取到该项目中的硬编码的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 |
sub、authorities、exp |
sub 为用户名,属于可枚举身份标识;authorities 为角色字符串,可被攻击者伪造 |
LoginController.login |
sub、exp |
sub 格式为 admin: + 用户名,属于可伪造身份标识 |
BlogController.checkBlogPassword |
sub、exp |
sub 为博客 ID 字符串,通常为低熵整数或可枚举业务标识 |
字段安全属性如下:
| 字段 |
含义 |
安全分析 |
sub |
用户名或博客 ID |
持久化标识或低熵业务标识,攻击者可获取、枚举或伪造 |
authorities |
角色字符串,如 ROLE_admin, |
权限字段,攻击者可直接伪造为管理员角色 |
exp |
过期时间 |
时间字段,攻击者可设置为未来时间 |
Payload 中不存在服务端生成并强制校验的随机高熵字段,也未绑定服务端会话状态、jti、nonce 或 Token 版本号。
3. Token 校验链路
JwtFilter 拦截所有 /admin/** 请求,并执行以下流程:
- 从
Authorization Header 中获取 JWT;
- 调用
JwtUtils.getTokenBody 解析 Token;
- 仅校验 JWT 签名和过期时间;
- 从 Payload 中直接提取
subject 和 authorities;
- 使用这些字段构造
UsernamePasswordAuthenticationToken;
- 将认证对象写入
SecurityContextHolder;
- 后续由 Spring Security 基于该认证上下文执行角色判断。
SecurityConfig 中的访问控制规则包括:
| 路由 |
权限要求 |
GET /admin/** |
hasAnyRole("admin", "visitor") |
其他 /admin/** |
hasRole("admin") |
由于角色权限直接来自 JWT Payload 中的 authorities 字段,攻击者在掌握硬编码 Secret 后,可以自行构造包含管理员权限的 Token。
4. Token 状态性
该 Token 校验机制属于无状态 Token 模型。服务端仅依赖签名密钥和过期时间判断 Token 是否有效,不进行以下校验:
- 不回查数据库确认用户是否存在;
- 不检查服务端会话状态;
- 不检查 Token 撤销列表;
- 不验证随机
jti 或 nonce;
- 不校验任何攻击者不可伪造的服务端字段。
5. 业务影响链路
JwtFilter 会将 JWT Payload 中的 subject 和 authorities 直接作为身份与权限依据写入 Spring Security 上下文。后续管理端控制器会信任该认证上下文执行敏感操作,例如:
- 博客管理;
- 评论管理;
- 站点设置;
- 账号管理;
- 密码修改;
- 其他
/admin/** 受保护接口操作。
这些业务逻辑不额外回查用户存在性或权限来源,因此伪造的管理员角色可直接生效。
6. 攻击结论
攻击者一旦获取硬编码 Secret abcdefghijklmnopqrstuvwxyz,即可伪造任意 JWT,例如:
- 设置
sub 为任意用户名;
- 设置
authorities 为 ROLE_admin,;
- 设置
exp 为未来时间。
该伪造 Token 可通过 JwtFilter 的签名校验,并被 Spring Security 识别为管理员身份。攻击者随后可访问所有 /admin/** 端点,执行博客管理、评论管理、站点设置、账号密码修改等敏感操作。
影响:
- 攻击者可伪造任意用户的 JWT
- 可冒充管理员或高权限账号访问敏感接口
- 用户身份认证机制失效
- 可能导致数据泄露、越权操作或账户接管
修复建议:
可以将JWT Secret放入系统环境变量中或者禁止使用默认值启动项目。
描述:
本项目是一个开源项目,任何用户都能获取到该项目中的硬编码的JWT Secret。同时,使用JWT Secret默认值启动项目时并没有任何警告提示,所以大多数用户可能不会修改此JWT Secret默认值,这可能导致攻击者伪造任意用户的权限令牌,从而绕过认证与授权机制,访问受保护接口。
密钥位置:
NBlog/blog-api/src/main/resources/application-dev.properties
Line 34 in b8e537c
漏洞类型:
风险等级:
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 进入默认运行环境。application.properties:1devProfileapplication-dev.properties:34token.secretKey被硬编码为abcdefghijklmnopqrstuvwxyzJwtUtils.java:24@Value("${token.secretKey}")注入JwtUtils相关方法JwtUtils.getTokenBody2. JWT Payload 分析
项目中存在多类 Token 生成逻辑,Payload 字段如下:
JwtLoginFilter.successfulAuthenticationsub、authorities、expsub为用户名,属于可枚举身份标识;authorities为角色字符串,可被攻击者伪造LoginController.loginsub、expsub格式为admin:+ 用户名,属于可伪造身份标识BlogController.checkBlogPasswordsub、expsub为博客 ID 字符串,通常为低熵整数或可枚举业务标识字段安全属性如下:
subauthoritiesROLE_admin,expPayload 中不存在服务端生成并强制校验的随机高熵字段,也未绑定服务端会话状态、
jti、nonce或 Token 版本号。3. Token 校验链路
JwtFilter拦截所有/admin/**请求,并执行以下流程:AuthorizationHeader 中获取 JWT;JwtUtils.getTokenBody解析 Token;subject和authorities;UsernamePasswordAuthenticationToken;SecurityContextHolder;SecurityConfig中的访问控制规则包括:GET /admin/**hasAnyRole("admin", "visitor")/admin/**hasRole("admin")由于角色权限直接来自 JWT Payload 中的
authorities字段,攻击者在掌握硬编码 Secret 后,可以自行构造包含管理员权限的 Token。4. Token 状态性
该 Token 校验机制属于无状态 Token 模型。服务端仅依赖签名密钥和过期时间判断 Token 是否有效,不进行以下校验:
jti或nonce;5. 业务影响链路
JwtFilter会将 JWT Payload 中的subject和authorities直接作为身份与权限依据写入 Spring Security 上下文。后续管理端控制器会信任该认证上下文执行敏感操作,例如:/admin/**受保护接口操作。这些业务逻辑不额外回查用户存在性或权限来源,因此伪造的管理员角色可直接生效。
6. 攻击结论
攻击者一旦获取硬编码 Secret
abcdefghijklmnopqrstuvwxyz,即可伪造任意 JWT,例如:sub为任意用户名;authorities为ROLE_admin,;exp为未来时间。该伪造 Token 可通过
JwtFilter的签名校验,并被 Spring Security 识别为管理员身份。攻击者随后可访问所有/admin/**端点,执行博客管理、评论管理、站点设置、账号密码修改等敏感操作。影响:
修复建议:
可以将JWT Secret放入系统环境变量中或者禁止使用默认值启动项目。