org.json与参数走私浅析
字数 2139 2025-10-01 14:05:52
org.json 解析特性与参数走私漏洞分析
一、org.json 库概述
org.json 是 Java Web 生态中一个轻量级的 JSON 构造和解析工具包,提供简洁的 API 进行 JSON 序列化与反序列化操作。该库还支持 JSON 与 XML、HTTP headers、Cookies 等格式的相互转换。
基本使用示例
JSONObject jsonobj = new JSONObject("{'name':'test','age':20}");
String name = jsonobj.getString("name");
二、org.json 解析过程深度分析
2.1 解析入口
通过 new JSONObject(String json) 构造方法进行 JSON 字符串解析,首先调用 nextClean() 方法获取下一个有效字符。
2.2 初始检查
- 检查 JSON 字符串是否以左花括号
{开头 - 不符合格式要求时抛出
JSONException异常
2.3 nextClean() 方法功能
从输入流中跳过所有空白字符(空格、制表符、换行符等),定位到第一个有效字符。
2.4 主解析循环
通过 while 循环对 JSON 字符串逐个字符读取,根据不同情况进行处理:
- case '\u0000':遇到 null 字符时抛出异常
- case '}':遇到右花括号时结束解析
- default:处理键值对(核心解析逻辑)
2.5 键值对解析流程
- 使用
nextSimpleValue()方法解析键名 - 检查下一个字符是否为冒号
:,否则抛出异常 - 检查键名重复性,发现重复键时抛出
syntaxError异常 - 使用
nextValue()方法解析属性值 - 将解析结果存储到当前 JSONObject 中
2.6 值解析机制
nextValue() 方法处理以下情况:
- 嵌套 JSON 对象
- Array 数组
- 其他类型通过
nextSimpleValue()处理
2.7 nextSimpleValue 方法解析逻辑
分两种情况处理属性值:
情况一:引号开头的内容
- 单/双引号开头时调用
nextString()方法 - 处理转义字符(\n、\t 等)和普通字符
- 支持 Unicode 字符处理
- 遇到匹配的结束引号时停止
情况二:非引号开头的内容
- 构造 StringBuilder
- 循环读取字符直到遇到 JSON 结构分隔符或控制字符
- 回退一个字符
- 调用
stringToValue()方法清理字符串并转换为对应 JSON 值
2.8 stringToValue 方法处理规则
对获取的内容进行规整处理:
- 检查字符串是否为空
- 判断是否为布尔值 "true" 或 "false"
- 判断是否为 "null"
- 检查是否为数字(仅处理 0-9 和负号
-情况) - 根据检查结果返回对应类型的值
三、org.json 解析特性总结
- 宽松的解析策略:允许属性不使用双引号包裹,支持单引号
- 重复键处理:不支持重复键,发现时会抛出异常
- 类型转换特性:对数字型输入有特殊处理规则
- Unicode 支持:完整支持 Unicode 字符处理
四、参数走私漏洞案例分析
4.1 漏洞场景
Web 应用 User 实体包含 roleId 属性(String 类型),认证拦截器对请求 JSON Body 中的 roleId 字段进行拦截:
JSONObject jsonObj = new JSONObject(body);
if (jsonObj.getString("roleId").equals("1")) {
// 鉴权逻辑,限制 roleId 更新操作
}
后端接口使用 Fastjson 进行参数解析,存在解析器差异。
4.2 漏洞原理
Fastjson 解析特性
- JSONScanner 会对以正号(+)、负号(-)或数字开头的字符串识别为数值
- 示例:
{"value":+1}解析后值为数字 1
org.json 解析特性
- 对非引号包裹的内容,只有 0-9 和负号(-)才会被识别为数字
- 正号(+)开头的内容会被原样输出为字符串
4.3 漏洞利用
构造攻击载荷
String body = "{\"roleId\":+1}";
JSONObject jsonobj = new JSONObject(body);
System.out.println("org.json parse result:" + jsonobj.getString("roleId"));
// 输出结果: "+1" (字符串)
User userByFastjson = com.alibaba.fastjson.JSONObject.parseObject(body, User.class);
System.out.println("fastjson parse result:" + userByFastjson.getRoleId());
// 输出结果: "1" (数字)
绕过效果
- org.json 将
+1解析为字符串 "+1" - Fastjson 将
+1解析为数字 1 - 成功绕过鉴权检查
4.4 其他攻击向量
Unicode 空字符利用
- json-c 对空字符会做截断处理
- org.json 库会保留 Unicode 空字符
- 通过在属性中增加 Unicode 空字符,结合重复 key 手法实现绕过
分号解析差异
- org.json 和 Gson 将分号
;识别为键值以外的分隔符 - 部分 JSON 解析组件会错误解析进入兜底逻辑
- 可能由于解析差异导致参数走私风险
五、防护建议
- 统一解析库:前后端使用相同的 JSON 解析库
- 严格输入验证:对输入数据进行严格类型和格式检查
- 安全配置:配置解析库使用严格模式
- 代码审计:重点关注多解析器共存场景
- 边界防护:在网关层进行有效的数据过滤和验证
六、总结
org.json 库的宽松解析特性与其它 JSON 解析库的差异可能导致参数走私漏洞。特别是在多解析器共存的环境中,解析差异可能被利用来绕过安全检测。开发人员应充分了解所使用的 JSON 解析库的特性,避免因解析差异导致的安全问题。在安全审计过程中,需要特别关注解析器差异可能带来的参数走私风险。
通过本文分析,我们深入了解了 org.json 的解析机制和可能存在的安全风险,为安全开发和代码审计提供了重要参考。