返回

揭开 Java 序列化背后:到底用不用?要不要放弃?

后端

Java 序列化与反序列化:理解、风险与防御

Java 序列化

Java 序列化是一个功能强大的机制,允许开发者将对象及其状态存储为二进制数据,以便日后还原。这个过程类似于将对象拍照,然后可以随时将其恢复。它广泛用于持久化数据、传输对象和实现远程方法调用 (RMI)。

Java 反序列化

反序列化是序列化过程的逆向操作。它将存储的二进制数据恢复为原始对象。这就像从照片中恢复原始场景一样。

反序列化漏洞的风险

反序列化漏洞是由于处理恶意序列化数据时软件中的缺陷引起的。这些漏洞允许攻击者执行任意代码、窃取敏感数据或破坏系统。最著名的反序列化漏洞之一是 CVE-2023-24055,它影响了 Java 并允许攻击者远程控制目标系统。

防御反序列化攻击

保护 Java 应用程序免受反序列化攻击至关重要。以下措施可以帮助防御这些攻击:

  • 避免反序列化来自不受信任来源的数据。
  • 使用签名验证序列化的数据。
  • 使用白名单限制可序列化的类。
  • 使用加密保护序列化的数据。
  • 使用沙盒隔离反序列化过程。

Java 序列化的谨慎使用

虽然 Java 序列化是一个有价值的工具,但它也存在安全风险。开发者应谨慎使用序列化,并采取适当的防御措施。

代码示例:防御反序列化攻击

// 白名单可序列化的类
import java.io.Serializable;

class SerializableClass implements Serializable {}

// 使用白名单过滤序列化对象
import java.io.ObjectInputStream;
import java.util.Arrays;
import java.util.List;

class DeserializationFilter implements ObjectInputFilter {

    private final List<Class<?>> allowedClasses;

    DeserializationFilter(Class<?>... allowedClasses) {
        this.allowedClasses = Arrays.asList(allowedClasses);
    }

    @Override
    public Object filterClass(Class<?> clazz) {
        return allowedClasses.contains(clazz) ? clazz : null;
    }
}

public class Example {

    public static void main(String[] args) {
        // 允许 SerializableClass 类被反序列化
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serializedBytes));
        ois.setObjectInputFilter(new DeserializationFilter(SerializableClass.class));

        // 反序列化对象
        Object object = ois.readObject();
    }
}

常见问题解答

  1. 序列化和反序列化有什么区别?
    序列化将对象存储为二进制数据,而反序列化将数据恢复为对象。

  2. 反序列化漏洞如何工作?
    恶意序列化数据触发软件中的缺陷,允许攻击者执行任意代码。

  3. 如何防御反序列化攻击?
    避免来自不受信任来源的数据,使用签名、白名单、加密和沙盒。

  4. Java 序列化是否应该弃用?
    不,但应谨慎使用并采取防御措施。

  5. 如何使用 Java 序列化实现远程方法调用?
    通过序列化参数和方法调用,并使用反序列化在远程系统上执行调用。