本文首發自https://www.secpulse.com/archives/95012.html,轉載請註明出處。html
Java 提供了一種對象序列化的機制,該機制中,一個對象能夠被表示爲一個字節序列,該字節序列包括該對象的數據、有關對象的類型的信息和存儲在對象中數據的類型。反序列化就是經過序列化後的字段還原成這個對象自己。但標識不被序列化的字段是不會被還原的。java
1)網站相應的session對象存儲在硬盤上,那麼保存在session中的內容就必須實現相關的序列化操做。git
2)若是使用的java對象要在分佈式中使用或者在rmi遠程調用的網絡中使用的話,那麼相關的對象必須實現java序列化接口。github
咱們最多見就是原生的java反序列化類型,其實java中有幾種方式能夠執行反序列化,本文目的也是對這幾種類型的反序列化方法進行概括和總結。apache
Java包中自帶的類InputStream和OutputStream,它們之間能夠互相轉化,使用writeObject序列化,使用readObject反序列化。json
import java.io.*; public class DeserializeDemo { public static void main(String [] args) { Employee e = null; try { FileInputStream fileIn = new FileInputStream("/tmp/employee.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); e = (Employee) in.readObject(); in.close(); fileIn.close(); }catch(IOException i) { i.printStackTrace(); return; }catch(ClassNotFoundException c) { System.out.println("Employee class not found"); c.printStackTrace(); return; } System.out.println("Deserialized Employee..."); System.out.println("Name: " + e.name); System.out.println("Address: " + e.address); System.out.println("SSN: " + e.SSN); System.out.println("Number: " + e.number); } }
Json序列化通常會使用jackson包,經過ObjectMapper類來進行一些操做,好比將對象轉化爲byte數組或者將json串轉化爲對象。數組
public static <T> String serialize(T t) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(t);
return jsonResult;
}
Fastjson是一個性能很好的Java語言實現的Json解析器和生成器,由來自阿里巴巴的工程師開發。具備極快的性能,超越任何其餘的Java Json Parser。Fastjson使用parseObject來進行反序列化。網絡
import com.alibaba.fastjson.JSON;
public class Person {
int age;
String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
String jsonString="{\"name\":\"hah\",\"age\":1}";
Person person = JSON.parseObject(jsonString, Person.class);
System.out.println(1);
}
}
Protocol Buffers 是一種輕便高效的結構化數據存儲格式,能夠用於結構化數據串行化,或者說序列化。它很適合作數據存儲或 RPC 數據交換格式。可用於通信協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。目前提供了 C++、Java、Python 三種語言的 API。session
proto.proto文件內容數據結構
package proto; message TestMsg{ optional string id = 1; optional string name = 2; }
序列化
public byte[] build(){ Proto.TestMsg.Builder builder = Proto.TestMsg.newBuilder(); builder.setId("ID的值"); builder.setName("Name的值"); Proto.TestMsg msg = builder.build(); return msg.toByteArray(); }
反序列化
Proto.TestMsg msg = Proto.TestMsg.parseFrom(message.returnByte()); System.out.Println(msg);
除了使用protobuf進行反序列化沒有出現過漏洞,其餘方式的序列化都曾出現過漏洞。下面將簡單介紹下漏洞,詳細的漏洞和exp構造方法你們能夠去網上搜索關鍵字查看(java幾個反序列化漏洞exp構造過程都十分精彩,推薦你們認真閱讀下)
Apache Commons Collections中實現了TransformedMap ,該類能夠在一個元素被添加/刪除/或是被修改時(即key或value:集合中的數據存儲形式便是一個索引對應一個值,就像身份證與人的關係那樣),會調用transform方法自動進行特定的修飾變換。
TransformedMap.decorate方法,預期是對Map類的數據結構進行轉化,該方法有三個參數。
經過對第三個參數經過構造ChainedTransformer鏈,經過一系列變化,最終執行系統命令。
Jackson是一套開源的java序列化與反序列化工具框架,可將java對象序列化爲xml和json格式的字符串及提供對應的反序列化過程。因爲其解析效率較高,目前是Spring MVC中內置使用的解析方式,該漏洞的觸發條件是ObjectMapper反序列化前調用了enableDefaultTyping方法。該方法容許json字符串中指定反序列化java對象的類名,而在使用Object、Map、List等對象時,可誘發反序列化漏洞,致使可執行任意命令。
fastjson在解析json的過程當中,支持使用autoType來實例化某一個具體的類,並經過json來填充其屬性值。而JDK自帶的類com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl中有一個私有屬性_bytecodes,其部分方法會執行這個值中包含的Java字節碼。經過注入惡意代碼到_bytecode,致使任意代碼執行漏洞。
注:Fastjson和Jackson Payload構造的方式都同樣,雖然解析函數不同,可是都是將json轉爲object,過程是相似的。
這些序列化漏洞的根本緣由是:沒有控制序列化的類型範圍。
仔細看的讀者會發現並無說起protobuf的反序列化漏洞,爲何在protobuf裏並無這些反序列化問題?
protobuf把一切都框住了,少了靈活性,天然就少漏洞。
注:IDL(Interface description language)文件:參與通信的各方須要對通信的內容須要作相關的約定(Specifications)。爲了創建一個與語言和平臺無關的約定,這個約定須要採用與具體開發語言、平臺無關的語言來進行描述。這種語言被稱爲接口描述語言(IDL),採用IDL撰寫的協議約定稱之爲IDL文件。
本文總結了java反序列化的幾種方式,並回顧了java幾個經典的漏洞以及對應的修復方案,但願經過本文,你們對java反序列化漏洞有更深入的認知。
參考連接:
http://hengyunabc.github.io/thinking-about-grpc-protobuf/
https://blog.csdn.net/u011721501/article/details/78555246
https://www.freebuf.com/sectool/165655.html
https://www.cnblogs.com/he1m4n6a/p/10131566.html
https://www.jianshu.com/p/e9e631285cb0
原文出處:https://www.cnblogs.com/he1m4n6a/p/10270696.html