Jackson中Json隐式数据类型转换与参数走私浅析
字数 1310 2025-08-20 18:17:59
Jackson中Json隐式数据类型转换与参数走私分析
0x00 前言
在Java中处理JSON数据时,隐式数据类型转换通常由JSON处理库自动完成。这些库会根据JSON值的格式和上下文推断并转换数据类型。本文以Jackson库为例,深入分析其隐式类型转换机制及可能导致的参数走私问题。
0x01 Jackson隐式转换(String->int)过程
基本示例
考虑以下User类定义:
public class User {
private int roleId;
public int getRoleId() {
return roleId;
}
public void setRoleId(int roleId) {
this.roleId = roleId;
}
}
通过@RequestBody传递User对象时,Spring Boot默认使用Jackson处理:
@RequestMapping(value = "/create")
public User demo(@RequestBody User user){
return user;
}
Jackson在默认情况下,即使JSON中的数字值被引号包围(表示字符串),也能成功转换为int类型的roleId。
转换过程分析
-
初始化阶段:
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); User user = objectMapper.readValue(body, User.class); -
解析流程:
- 调用
_readMapAndClose方法初始化解析器 - 创建
DefaultDeserializationContext上下文对象 - 读取
JsonToken并根据类型处理数据
- 调用
-
反序列化处理:
- 通过
BeanDeserializer的deserialize方法处理 - 在
vanillaDeserialize方法中遍历JSON字段 - 对于int类型属性,使用
IntegerDeserializer#deserialize处理
- 通过
-
字符串到整数的转换:
- 检查JSON Token类型
- 对于字符串Token(VALUE_STRING),调用
_parseIntPrimitive方法 - 处理前会调用
trim()方法清理空格 - 最终通过
NumberInput.parseInt完成转换
0x02 参数走私案例
场景描述
应用使用User类的roleId(int类型)表示用户角色类型,同时在拦截器中使用Fastjson处理请求体:
Map<String, Object> params = JSON.parseObject(body, HashMap.class);
if(params.get("roleId").equals("1")){
// 鉴权逻辑
}
利用差异
-
空格处理差异:
- Jackson会忽略字符串中的空格
- Fastjson不会忽略空格
String body = "{\"roleId\":\"1 \"}"; // Jackson解析结果为1 // Fastjson解析结果为"1 ",不等于"1" -
前导零处理:
- Jackson会忽略数字字符串前导的零
- Fastjson会保留原始字符串形式
String body = "{\"roleId\":\"00001\"}"; // Jackson解析结果为1 // Fastjson解析结果为"00001"
攻击向量
通过构造特殊格式的JSON,利用不同解析器的处理差异绕过安全检测:
{
"roleId": "1 " // 带空格的字符串
}
或
{
"roleId": "00001" // 带前导零的字符串
}
0x03 其他类型处理
long类型处理
_parseLongPrimitive方法同样会:
- 忽略字符串中的空格
- 处理前导零
- 支持从字符串到long的隐式转换
double类型处理
类似地,double类型的处理也会:
- 自动清理字符串中的空格
- 完成字符串到double的转换
Gson的类似行为
Gson库也存在类似的隐式转换逻辑:
String body = "{\"roleId\":\"123456789 \"}";
Gson gson = new Gson();
User user = gson.fromJson(body, User.class);
// 解析结果为123456789
防御建议
- 统一JSON解析器:确保应用各层使用相同的JSON处理库
- 严格类型检查:在拦截器中明确检查数据类型
- 输入规范化:对输入值进行trim等规范化处理
- 使用严格模式:配置解析器不自动进行类型转换
- 白名单验证:对关键字段进行严格的白名单验证
总结
Jackson等JSON库的隐式类型转换机制虽然提供了便利,但也带来了潜在的安全风险。特别是在混合使用不同JSON库或存在安全检测逻辑时,可能被利用进行参数走私攻击。开发者应当充分了解所使用的JSON库的行为特性,并在安全关键路径上进行严格的数据验证。