反序列化攻击原理及防御措施(已解决)
**java序列化算法透析**
Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。Java序列化API提供一种处理对象序列化的标准机制。在这里你能学到如何序列化一个对象,什么时候需要序列化以及Java序列化的算法,我们用一个实例来示范序列化以后的字节是如何描述一个对象的信息的。
序列化的必要性
Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端。
这就需要有一种可以在两端传输数据的协议。Java序列化机制就是为了解决这个问题而产生
如何进行序列化
public class Java_Test {
public static void main(String args[]) throws Exception {
Peoper peoper = new Peoper();
// peoper1.setAge(6);
peoper.setName("zy");
//peoper1.setJob("6666666666");
// 将序列化对象写入文件object.txt中
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(peoper);
os.close();
// 从文件object.txt中读取数据
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
//MyObjectInputStream ois = new MyObjectInputStream(fis);
//ObjectInputStream ois = new ObjectInputStream(fis);
// 通过反序列化恢复对象obj
Peoper peoper1 = (Peoper) ois.readObject();
System.out.println(peoper1);
ois.close();
}
}
序列化漏洞发生的位置
在反序列化的过程中,我们通过ObjectInputStream来进行字节码的读取,但是在该类中没有对将要序列化的对象进行校验。攻击者则可以通过构造POC的方式,把自己构造的对象提交到服务器,服务器在反序列化的工程中会执行readObject方法,而此方法可以在构造的对象中重写。
通过改变transferedMap的key或则value值来触发transferChain的系统函数的执行,从而控制服务器,造成严重的损失。
解决方案原理核心
通过重写ObjectInputStream的resolveClass方法对即将序列化的对象进行校验(在反序列化之前进行),从而达到避免反序列化漏洞的风险。
解决方法具体代码如下
public class MyObjectInputStream extends ObjectInputStream {
public MyObjectInputStream(InputStream in) throws IOException {
super(in);
}
protected MyObjectInputStream() throws IOException, SecurityException {
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (desc == null) {
return super.resolveClass(desc);
}
if (!desc.getName().equals(Peoper.class.getName())) {
throw new InvalidClassException("不能序列化,可能有攻击",desc.getName());
}
return super.resolveClass(desc);
}
}
在实际开发过程中代码示例
public class MyObjectInputStream extends ObjectInputStream {
public MyObjectInputStream(InputStream in) throws IOException {
super(in);
}
protected MyObjectInputStream() throws IOException, SecurityException {
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (desc == null) {
return super.resolveClass(desc);
}
if (!desc.getName().contains("被序列化对象包名")) {
throw new InvalidClassException("不能序列化,可能有攻击",desc.getName());
}
return super.resolveClass(desc);
}
}
以上是个人处理方式以及见解,如有不妥之处,希望之处!!!!