目录
在这篇博客中,我们将深入探讨 Java 反序列化和 Shiro 反序列化的概念及过程。
一、Java 反序列化
在 Java 中,与其他编程语言不同,它具有独特的序列化和反序列化机制。
(一)序列化方法
在ObjectOutputStream
类中有一个writeObject
方法,它可以实现序列化,其作用是把对象转换成字节流,便于保存或者传输,类似于其他编程语言中的serialize
方法。
以下是一个简单的 Java 序列化示例代码:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
class Person implements java.io.Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Person person = new Person("John", 30);
try (FileOutputStream fos = new FileOutputStream("person.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(person);
System.out.println("Serialized object successfully.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
(二)反序列化方法
而在ObjectInputStream
类中有一个readObject
方法,它是用来反序列化的,就像其他编程语言中的unserialize
方法,其作用是把字节流还原成对象。
以下是对应的反序列化代码:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
class Person implements java.io.Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("person.ser");
ObjectInputStream ois = new ObjectInputStream(fis)) {
Person person = (Person) ois.readObject();
System.out.println("Deserialized object: Name - " + person.name + ", Age - " + person.age);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
二、Shiro 反序列化
Shiro 反序列化主要是因为 Apache Shiro 提供了一个叫做rememberMe
的功能。当用户登录成功后,会生成经过加密并且编码的 cookie 保存在浏览器中,方便用户日常使用。
(一)服务器对 cookie 的处理流程
- 获取浏览器上保存的 cookie。
- 将其进行 base64 解码。
- 进行 AES 解密。
- 最后将其进行反序列化进行校验。
(二)漏洞产生原因及利用
如果程序员没有去修改 AES 的默认密钥或者修改之后过于简单,那么攻击者就可以通过进行 cookie 的重构来利用这个漏洞。具体步骤如下:
- 构造恶意代码。
- 将恶意代码进行序列化。
- 使用 AES 加密(假设密钥已爆破出来)。
- 进行 base64 编码,形成新的 cookie。
当服务器按照正常流程处理这个新的 cookie 时,就会加载攻击者构造的恶意代码,从而在服务端触发恶意代码。
希望这篇博客能帮助你更好地理解 Java 反序列化和 Shiro 反序列化的概念及过程。如果有任何疑问或建议,欢迎在评论区留言。