什么是序列化反序列化
定义
序列化(Serialization)是指将对象的状态信息转换为可以存储或传输的形式的过程。这个过程中,对象的公有属性和私有属性以及对象的类型信息被转换为一种可存储或传输的格式,如XML、JSON、二进制等。序列化后的数据可以写入文件、数据库或者通过网络传输到另一个系统。
反序列化(Deserialization)是序列化的逆过程,它将存储或传输的数据格式转换回原来的对象状态。这意味着可以重新创建出原先的对象,包括其类型、属性等信息。反序列化使得对象的跨平台存储和通信成为可能。
在网络通信中,序列化使得对象能够在网络中进行传输。例如,一个客户端应用程序可以序列化一个对象并通过网络发送给服务器,服务器接收到这个序列化的对象后,可以进行反序列化来恢复成原始对象进行处理。
在数据存储中,序列化允许对象的状态被保存下来,以后可以通过反序列化恢复对象的状态进行进一步的处理或显示。 更加简单来说这个过程,序列化,就是将对象转化成数据进行存储,而反序列化,就是将数据进行转化成对象进行代码执行
漏洞的产生
未校验客户的输入,导致数据序列化与反序列的过程中,将恶意的数据当成对象进行了命令执行,导致漏洞产生
语言中关键函数有哪些?
php
serialize()` 和 `unserialize()
- `serialize()` 函数可以将PHP的值保存为一个字符串,这样可以用于存储或传递PHP值,同时保持它们的类型和结构。
- `unserialize()` 函数可以将通过`serialize()`函数生成的字符串还原回PHP的值。
json_encode() 和 json_decode()
json_encode() 函数用于将PHP变量编码成JSON格式的字符串,这样可以轻松地与JavaScript交互或存储数据。
json_decode() 函数用于将JSON格式的字符串解码成PHP变量。
var_export() 和 eval():
var_export() 函数可以将变量的结构转换为PHP代码。结合eval()函数,可以实现反序列化,但请注意,使用eval()可能会带来安全风险,因为它会执行任意PHP代码。
XML序列化:
PHP提供了如SimpleXMLElement或DOMDocument类,可以用来生成和处理XML数据。这对于需要与遵循XML标准的系统交换数据时非常有用。
igbinary:
igbinary是一个PHP扩展,提供了更紧凑的二进制格式来序列化PHP数据结构,相比于标准的serialize函数,它可以生成更小的结果,同时速度更快。使用igbinary需要先安装这个扩展,然后使用它的igbinary_serialize()和igbinary_unserialize()函数
msgpack:
msgpack是一个高效的二进制序列化格式,它允许你在多种语言之间交换数据,对于PHP来说,你可以通过安装msgpack扩展来使用它。与igbinary类似,msgpack提供了msgpack_pack()和msgpack_unpack()函数进行序列化和反序列化操作。
java
Serializable 接口:
java.io.Serializable 是一个标记接口,它不包含任何方法。当一个类实现了这个接口,它就表明这个类的对象可以被序列化。序列化机制会忽略没有实现这个接口的类。
ObjectOutputStream 类:
java.io.ObjectOutputStream 类是将Java对象的原始数据类型和图形写入OutputStream的序列化流。只有支持java.io.Serializable或java.io.Externalizable接口的对象才能通过这个流进行序列化。
// 使用ObjectOutputStream序列化对象
FileOutputStream fileOut = new FileOutputStream("object.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(yourObjectInstance);
out.close();
fileOut.close();
这个类有多种写操作方法,包括writeObject()、writeInt()、writeDouble()等,用于序列化不同类型的数据。
ObjectInputStream 类:
java.io.ObjectInputStream 类是用于从流中读取字节并将这些字节反序列化成对象的反序列化流。它的readObject()方法可以用来读取之前序列化的对象。
// 使用ObjectInputStream反序列化对象
FileInputStream fileIn = new FileInputStream("object.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
YourClass yourObjectInstance = (YourClass) in.readObject();
in.close();
fileIn.close();
类似地,这个类也有多种读操作方法,如readInt()、readDouble()等,用于反序列化不同类型的数据。
Externalizable 接口:
java.io.Externalizable 继承了Serializable接口,并添加了两个方法:writeExternal() 和 readExternal(),这两个方法由类实现,以允许类包含它们自己的序列化和反序列化逻辑。
transient 关键字:
在类的字段声明中使用transient关键字可以防止字段被序列化。对于不希望被序列化的敏感字段或那些可以根据其他字段推导出来的字段,可以使用transient关键字。
static 关键字:
静态字段不直接属于任何一个特定的实例,而是属于类本身。因此,它们不是对象的一部分,所以在序列化时不会被写入流中。
对于XML和JSON等格式的序列化/反序列化,这些类库提供了一套完整的API来处理数据转换:
Jackson:
一个高性能的JSON处理库,它提供了序列化和反序列化的功能。它也支持从JSON到POJO(普通Java对象)、从POJO到JSON,甚至是支持更复杂的数据处理任务。
Gson:
Google的库用于将Java对象转换成它们的JSON表示形式,也可以从JSON字符串转换回Java对象。Gson允许自定义转换规则,并且对于复杂对象图形处理也非常灵活。
JAXB (Java Architecture for XML Binding):
JAXB允许Java开发人员通过对应的注解在Java类和XML文档之间进行映射。它提供了一个便捷的方式来处理XML数据,而不必关心它的实际解析。
序列化与反序列化原理分析
利用
Java 序列化机制允许开发者将对象转换成一个字节流(序列化),然后可以将这个字节流再转换回对象(反序列化)。这是一种在网络间或者在进行持久化存储前后传输对象状态的简便方式。
在这里我们利用写一个简单的测试程序,如下代码创建了 Person 类,实现了 Serializable 接口,并重写了 readObject 方法,在方法中使用 Runtime 执行命令弹出计算器。
-
import java.io.*;
public class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
// 潜在危险的代码:在反序列化时执行系统命令
Runtime.getRuntime().exec("open -a Calculator.app");
}
}-
然后我们将这个类序列化并写在文件中,随后对其进行反序列化,就触发了命令执行。
-
public class SerializableTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Person person = new Person("zhangsan", 24);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("abc.txt"));
oos.writeObject(person);
oos.close();
FileInputStream fis = new FileInputStream("abc.txt"); ObjectInputStream ois = new ObjectInputStream(fis);
ois.readObject();
ois.close();
}
}
-
-
以下是对示例程序的详细分析和思维导图的简要说明:
1. 类定义与序列化
Person 类实现了 java.io.Serializable 接口,这是一个标记接口,它告诉JVM这个类的对象可以被序列化。
java复制public class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
Runtime.getRuntime().exec("open -a Calculator.app");
}
}
2. 恶意代码注入













请登录后查看评论内容