ObjectInputFilter.FilterInfo 是 Java 中的一个静态内部接口,属于 java.io 包的一部分。它是在 Java 9 中引入的,作为对象反序列化过滤机制的一部分,用于提高 Java 反序列化的安全性。

接口定义

public static interface ObjectInputFilter.FilterInfo {
    // 获取正在反序列化的类
    Class<?> serialClass();
    
    // 获取数组长度(如果是数组对象)
    long arrayLength();
    
    // 获取当前对象的深度(嵌套层级)
    long depth();
    
    // 获取已经读取的字节数
    long streamBytes();
    
    // 获取当前正在被反序列化的对象的引用
    ObjectInputFilter.FilterInfo serialClass(Class<?> clazz);
}

主要方法说明

方法 描述
serialClass() 返回正在被反序列化的类,如果类还未确定则返回 null
arrayLength() 如果是数组对象,返回数组的长度;否则返回 -1
depth() 返回当前对象在反序列化流中的嵌套深度(从 1 开始)
streamBytes() 返回已经读取的字节数
serialClass(Class<?>) 设置当前正在被反序列化的类

使用场景

FilterInfo 接口主要用于自定义的 ObjectInputFilter 中,在反序列化过程中提供关于当前正在反序列化的对象的信息,以便过滤器决定是否允许反序列化继续。

示例代码

import java.io.*;
import java.util.ArrayList;

public class ObjectFilterExample {
    
    public static void main(String[] args) {
        // 创建对象输入流并设置过滤器
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("data.ser"))) {
            
            // 设置自定义过滤器
            ois.setObjectFilter(info -> {
                // 获取正在反序列化的类
                Class<?> clazz = info.serialClass();
                
                // 如果是 null(基本类型或数组),允许
                if (clazz == null) {
                    return ObjectInputFilter.Status.ALLOWED;
                }
                
                // 检查类名
                String className = clazz.getName();
                
                // 只允许特定的类被反序列化
                if (className.startsWith("java.util.ArrayList") ||
                    className.startsWith("java.lang.String") ||
                    className.startsWith("com.example.")) {
                    return ObjectInputFilter.Status.ALLOWED;
                }
                
                // 检查数组长度
                if (clazz.isArray() && info.arrayLength() > 1000) {
                    System.out.println("数组太长,拒绝反序列化");
                    return ObjectInputFilter.Status.REJECTED;
                }
                
                // 检查嵌套深度
                if (info.depth() > 10) {
                    System.out.println("对象嵌套太深,拒绝反序列化");
                    return ObjectInputFilter.Status.REJECTED;
                }
                
                // 检查流大小
                if (info.streamBytes() > 1024 * 1024) { // 超过 1MB
                    System.out.println("流太大,拒绝反序列化");
                    return ObjectInputFilter.Status.REJECTED;
                }
                
                // 默认拒绝
                return ObjectInputFilter.Status.REJECTED;
            });
            
            // 读取对象
            Object obj = ois.readObject();
            System.out.println("反序列化成功: " + obj);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

// 使用 lambda 表达式的更简洁示例
class SimpleFilterExample {
    
    public static void main(String[] args) {
        // 创建一个简单的过滤器,只允许 ArrayList 和 String
        ObjectInputFilter filter = info -> {
            Class<?> clazz = info.serialClass();
            
            if (clazz == null) {
                return ObjectInputFilter.Status.ALLOWED;
            }
            
            if (clazz == ArrayList.class || clazz == String.class) {
                return ObjectInputFilter.Status.ALLOWED;
            }
            
            return ObjectInputFilter.Status.REJECTED;
        };
        
        // 使用过滤器
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("data.ser"))) {
            ois.setObjectFilter(filter);
            Object obj = ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

过滤器状态返回值

过滤器方法需要返回一个 ObjectInputFilter.Status 枚举值:

状态 含义
ALLOWED 允许反序列化
REJECTED 拒绝反序列化
UNDECIDED 未决定,让后续的过滤器决定

主要用途

  1. 安全防护:防止反序列化攻击,只允许信任的类被反序列化
  2. 资源控制:限制数组长度、对象深度、流大小,防止内存溢出
  3. 调试监控:记录反序列化的对象信息
  4. 兼容性控制:确保只有兼容的类版本被反序列化

注意事项

  • FilterInfo 接口是在反序列化过程中动态提供信息的
  • 过滤器应该尽快做出决定,避免影响性能
  • 可以链式组合多个过滤器
  • 对于数组,serialClass() 返回数组类型,arrayLength() 提供长度信息
  • 过滤器可以在系统级别、流级别或对象级别设置

这个接口是 Java 反序列化安全机制的核心部分,通过它可以有效防范不安全的反序列化操作。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐