渗透测试--JWT攻防(一)
字数 1515 2025-08-10 09:43:39
JWT攻防教学文档
一、JWT简介
JSON Web Token (JWT) 是一种用于安全地在不同实体之间传递信息的开放标准(RFC 7519),主要用于身份验证和授权领域。
主要特点:
- 自包含:不需要在服务器端存储会话信息
- 适用于分布式系统和微服务架构
- 在网络应用程序和服务之间传递声明(claims)信息
二、JWT结构
JWT由三部分组成,使用点号(.)分隔:
Header.Payload.Signature
1. Header (头部)
- 包含令牌元信息,如加密算法
- Base64编码但未加密
- 主要字段:
alg(Algorithm):指定签名算法,如HS256(HMAC SHA-256)typ(Type):令牌类型,通常为"JWT"
示例:
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload (载荷)
包含三类声明(claims):
- 注册声明(Registered claims):预定义标准声明
iss(issuer):发行者sub(subject):主题(通常为用户ID)exp(expiration time):过期时间iat(issued at):签发时间
- 私有声明(Private claims):用户自定义
- 公共声明(Public claims):应公开定义的声明
示例:
{
"sub": "1234567890",
"name": "toboshuse",
"iat": 1697790142
}
3. Signature (签名)
用于验证令牌完整性和真实性,生成方式:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
三、JWT工作原理
生成令牌流程:
- 创建头部(Header),选择加密算法
- 创建载荷(Payload),包含声明信息
- 生成签名(Signature),使用密钥和算法
- 组合三部分形成完整JWT
验证令牌流程:
- 接收方拆分JWT为三部分
- 使用相同算法和密钥重新计算签名
- 比较新签名与原始签名
- 验证声明(如检查过期时间)
四、Java中的JWT实现
Maven依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
示例代码:
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Claims;
public class JwtExample {
private static final String SECRET_KEY = "mySecretKey";
// 创建JWT
private static String createJWT(String subject, String name) {
return Jwts.builder()
.setSubject(subject)
.claim("name", name)
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
// 验证JWT
private static Claims parseJWT(String jwt) {
try {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(jwt)
.getBody();
} catch (Exception e) {
return null;
}
}
}
五、JWT攻击手法
攻击1:伪造令牌
原理:利用JWT可被解密的特性,修改Payload部分提升权限
步骤:
- 获取正常JWT令牌
- 解码Payload部分
- 修改关键字段(如将
sub改为"administrator") - 重新编码Payload
- 替换原Payload部分
防御:
- 使用强密钥
- 验证签名有效性
- 不信任客户端提供的令牌
攻击2:签名算法设为None
原理:当alg设为"None"时,服务器可能不验证签名
步骤:
- 修改Header部分,将
alg改为"None" - 移除Signature部分
- 修改Payload提升权限
- 发送伪造的JWT
防御:
- 生产环境禁用"None"算法
- 严格验证签名算法
- 拒绝没有签名的JWT
六、实战演练
靶场1:未验证签名的JWT
- 登录获取普通用户JWT
- 解码Payload,修改
sub为"administrator" - 重新编码并替换原Payload
- 使用伪造JWT访问/admin路径
靶场2:有缺陷的签名验证
- 登录获取JWT
- 修改Header将
alg设为"None" - 移除Signature部分
- 修改Payload提升权限
- 使用伪造JWT访问特权接口
七、安全建议
-
密钥管理:
- 使用强密钥(足够长度和复杂度)
- 定期轮换密钥
- 不要硬编码密钥
-
算法选择:
- 避免使用"None"算法
- 优先使用RS256而非HS256(非对称优于对称)
- 明确指定允许的算法列表
-
声明验证:
- 验证所有关键声明(iss, sub, exp等)
- 检查令牌有效期
- 验证发行者(iss)是否可信
-
传输安全:
- 使用HTTPS传输JWT
- 避免在URL中传递JWT
- 考虑使用HttpOnly和Secure标志的Cookie
-
其他:
- 实现令牌撤销机制
- 限制令牌有效期
- 监控异常令牌使用