snack4 - Json 序列化的安全控制
序列化类型安全控制,对日常的应用开发尤其重要。(涉及序列化的框架,都会涉及安全问题)
情况1:默认只访问字段(避免触发行为,比较安全)
默认是这个状态:
- 不允许使用 setter, getter
- 不允许使用 有参数的构造方法(但允许
record或全部只读字段的类使用)
java17 后,模块化的类可能会有访问权限问题。(可通过 --add-opens 开放模块)
情况2:默认状态下启用 Feature.Read_AutoType (比较安全)
涉及特性(一般不需要启用):
Feature.Read_AutoType
情况3:只启用 setter, getter 和 parameterized constructor(比较安全)
启用这三个特性后,模块化类的有访问权限问题可以启用。涉及特性:
Feature.Read_OnlyUseGetter //绝不访问字段读
Feature.Write_OnlyUseSetter //绝不访问字段写
Feature.Write_AllowParameterizedConstructor
情况4:(情况2 + 情况3)需要加黑白名单机制(不安全)
(比较)如果要序列化 Exception 类,需要启用 情况2 + 情况3 的多种特性,会比较不安全。需要加黑白名单机制
//序列化
String json = ONode.ofBean(e,
Feature.Write_ClassName, //write json
Feature.Read_OnlyUseGetter //read bean
).toJson();
//反序列化
NullPointerException e = ONode.ofJson(json,
Feature.Write_OnlyUseSetter,
Feature.Write_AllowParameterizedConstructor,
Feature.Read_AutoType
).toBean();
白黑名单结合参考:
public class TypeSafety {
@Test
public void case1() {
Options options = Options.of();
//使用 ObjectFactory 模拟白名单(可选)
options.addCreator(User.class, (opts, node, clazz) -> new User());
options.addCreator(Order.class, (opts, node, clazz) -> new Order());
//使用 ObjectPatternFactory 模拟黑名单(必选)
options.addFactory(new ObjectPatternFactory<Object>() {
@Override
public boolean calCreate(Class<?> clazz) {
return true;
}
@Override
public Object create(Options opts, ONode node, Class<?> clazz) {
if(Throwable.class.isAssignableFrom(clazz) == false) { //其它类,只以允许 Throwable
throw new SnackException("");
} else {
return null; //交给框架自动处理
}
}
});
//效果测试
Assertions.assertThrows(SnackException.class, () -> {
ONode.deserialize("{id:1}", UserModel.class, options);
});
ONode.deserialize("{id:1}", Map.class, options);
}
}