一、json反序列化问题
参照这篇文章:https://www.freebuf.com/articles/web/258827.html
其实@RequestBody底层是jackson,程序员往往用@RequestBody处理fastjson的JSONObject,以方便快速解析json (起码我们公司是这样)
对应的postman的请求截图:
这种方式是没有反序列化漏洞的(编写文章时的版本为springboot2.4),但是安全人员最担心的是使用fastjson的
com.alibaba.fastjson.JSON.parse
com.alibaba.fastjson.JSON.parseObject
两个函数处理json串的时候因为黑名单和白名单的编写不规范导致的安全风险
在openrasp1.3.6中覆盖了fastjson以上两个函数和jackson的一系列解析函数,所以不用过于担心反序列化安全问题
接下来我们讨论一下反序列化的安全编码规范
1)jackson的安全编码:
1)禁用enableDefaultTyping
2)禁用JsonTypeInfo
3)使用activateDefaultTyping + 白名单过滤器(白名单中的类禁止包含readObject函数)
其中activateDefaultTyping的安全编码举例如下:
ObjectMapper om = new ObjectMapper();
BasicPolymorphicTypeValidator validator = BasicPolymorphicTypeValidator.builder()
// 信任 com.hyit. 包下的类
.allowIfBaseType("com.hyit.")
.allowIfSubType("com.hyit.")
// 信任 Collection、Map 等数据结构
.allowIfSubType(Collection.class)
.allowIfSubType(Number.class)
.allowIfSubType(Map.class)
.allowIfSubType(Temporal.class)
.allowIfSubTypeIsArray()
.build();
om.activateDefaultTyping(validator,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
如果某些场景,例如需要序列化、反序列化到redis数据库时
1.只能使用activateDefaultTyping函数,并且必须白名单校验
2.所有加入到白名单中的类不能包含readObject函数
2)fastjson的安全编码:
一、添加autotype白名单,添加白名单有三种方式
1. 在代码中配置
ParserConfig.getGlobalInstance().addAccept("com.taobao.pac.client.sdk.dataobject.");
如果有多个包名前缀,分多次addAccept
2. 加上JVM启动参数
-Dfastjson.parser.autoTypeAccept=com.taobao.pac.client.sdk.dataobject.,com.cainiao.
//如果有多个包名前缀,用逗号隔开
3. 通过fastjson.properties文件配置。
支持通过类路径的fastjson.properties文件来配置,配置方式如下:
fastjson.parser.autoTypeAccept=com.taobao.pac.client.sdk.dataobject.,com.cainiao.
// 如果有多个包名前缀,用逗号隔开safeMode模式
二、safeMode打开后,完全禁用autoType。
1. 在代码中配置
ParserConfig.getGlobalInstance().setSafeMode(true);
如果使用new ParserConfig的方式,需要注意单例处理,否则会导致低性能full gc
2. 加上JVM启动参数
-Dfastjson.parser.safeMode=true
3. 通过fastjson.properties文件配置。
通过类路径的fastjson.properties文件来配置,配置方式如下:
fastjson.parser.safeMode=true
不论是jackson还是fastjson需要将数据按照以下方式与redis存取的时候,都必须使用白名单严格限制哪些类能被序列化和反序列化
jackson的例子
["java.util.ArrayList",[{"@class":"com.model.app","id":72,"uuid":"c4d7fc52-4096-4c79-81ef-32cb1b87fd28","type":2}]]
fastjson的例子
{"@type":"com.what21.fastjson.fj03.Group","id":"manager","name":"小奋斗教程","userList":[]}
1)jdk的选择 jdk使用1.8u271或以上版本 jdk使用11.09或以上版本
以上版本已经解决已知的安全校验被绕过的问题
以上版本默认可以缓解rmi或ldap协议被反序列化攻击的风险
2)常见高危组件的选用
fastjson 1.2.75或以上版本,参照前文的代码规范
jackson 2.10.x或以上版本,参照前文的代码规范
二、如何限制敏感字段直接进行json转换
使用@JsonIgnore
public class user {
public int id;
public String name;
@JsonIgnore
public String password;
}
比如user表,在password这个属性上添加@JsonIgnore,就会set和get方法都不会出现password,也就是这个属性不会被格式化
注解get上,就会发现前端不会显示password的数据,而注解在set上,后端就拿不到前端传过来的password的数据
对应的也可以直接使用@JsonIgnoreProperties作用在类上
@JsonIgnoreProperties({ "password" })
public class user {
public int id;
public String name;
public String password;
}
或者扩展 BaseCommandController 的 Spring 应用程序可以替代 initBinder(HttpServletRequest request, ServletRequestDataBinder binder) 方法
以此获取对 Spring 模型绑定器的引用
@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
binder.setDisallowedFields(new String[]{"details.role", "details.age", "password"});
}
这个方法的本质是修改WebDataBinder的setDisallowedFields字段的内容
来源:oschina
链接:https://my.oschina.net/9199771/blog/4876577