类型注册与安全
本页介绍类注册机制和安全配置。
类注册
ForyBuilder#requireClassRegistration 可用于禁用类注册。这将允许反序列化未知类型的对象,这更灵活但如果类包含恶意代码可能不安全。
除非你能确保环境是安全的,否则不要禁用类注册。当禁用此选项时,反序列化未知/不受信任的类型时,init/equals/hashCode 中的恶意代码可能会被执行。
类注册不仅可以降低安全风险,还可以避免类名序列化成本。
按 ID 注册
你可以使用 API Fory#register 注册类:
Fory fory = xxx;
fory.register(SomeClass.class);
fory.register(SomeClass1.class, 1);
注意,类注册顺序很重要。序列化和反序列化端应该具有相同的注册顺序。
按名称注册
按 ID 注册类会有更好的性能和更小的空间开销。但在某些情况下,管理一堆类型 ID 很复杂。在这种情况下,建议使用 API register(Class<?> cls, String namespace, String typeName) 按名称注册类:
fory.register(Foo.class, "demo", "Foo");
如果类型没有重复的名称,namespace 可以留空以减少序列化大小。
不要使用此 API 注册类,因为与按 ID 注册类相比,它会大大增加序列化大小。
安全配置
类检查器
如果你调用 ForyBuilder#requireClassRegistration(false) 来禁用类注册检查,你可以通过 ClassResolver#setClassChecker 设置 org.apache.fory.resolver.ClassChecker 来控制哪些类允许序列化。
例如,你可以允许以 org.example.* 开头的类:
Fory fory = xxx;
fory.getClassResolver().setClassChecker(
(classResolver, className) -> className.startsWith("org.example."));
AllowListChecker
Fory 提供了 org.apache.fory.resolver.AllowListChecker,这是一个基于允许/禁止列表的检查器,用于简化类检查机制的自定义:
AllowListChecker checker = new AllowListChecker(AllowListChecker.CheckLevel.STRICT);
ThreadSafeFory fory = new ThreadLocalFory(classLoader -> {
Fory f = Fory.builder().requireClassRegistration(true).withClassLoader(classLoader).build();
f.getClassResolver().setClassChecker(checker);
checker.addListener(f.getClassResolver());
return f;
});
checker.allowClass("org.example.*");
你可以使用此检查器或自己实现更复杂的检查器。
限制最大反序列化深度
Fory 提供 ForyBuilder#withMaxDepth 来限制最大反序列化深度。默认最大深度为 50。
如果达到最大深度,Fory 将抛出 ForyException。这可用于防止恶意数据导致堆栈溢出或其他问题。
Fory fory = Fory.builder()
.withLanguage(Language.JAVA)
.withMaxDepth(100) // 设置自定义最大深度
.build();
最佳实践
- 在生产环境中始终启用类注册:使用
requireClassRegistration(true) - 使用基于 ID 的注册以获得性能:数字 ID 比字符串名称更快
- 保持一致的注册顺序:序列化和反序列化端的顺序相同
- 设置适当的最大深度:防止堆栈溢出攻击
- 使用 AllowListChecker 进行细粒度控制:当你需要灵活的类过滤时