JSON解析差异-风险研究
字数 1724 2025-08-22 12:22:24

JSON解析差异与安全风险研究

1. JSON解析差异概述

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,广泛应用于客户端与服务器之间的数据传输。然而,由于缺乏严格的规范定义,不同JSON解析器在处理相同JSON文档时可能存在差异,从而导致潜在的安全风险。

1.1 问题根源

  • 规范不严格:官方JSON RFC(如8259)对一些细节提供了宽泛的规则
  • 多种解析规范共存
    • IETF JSON RFC (8259及之前版本)
    • ECMAScript标准
    • JSON5(扩展规范,添加注释、无引号字符串等便利功能)
    • HJSON(类似JSON5但有不同设计选择)

2. 主要解析差异类型及安全风险

2.1 重复键处理差异

示例

{
  "a": 1,
  "a": 2
}

不同解析器处理方式:

  • Python(jsonschema):以后出现的键值为准(a=2)
  • Go(jsonparser):以先出现的键值为准(a=1)

安全风险

  • 当系统使用多个解析器时(如前端用Go,后端用Python),可能导致业务逻辑绕过
  • 实验案例:利用Python Flask作为代理校验层,Go处理实际计算逻辑,通过重复键绕过校验

2.2 字符截断与Unicode处理差异

示例payload

{
  "test": 1,
  "test\\ud800": 2
}

不同解析器处理方式:

  • Python 2.x:可能将非法Unicode字符截断,导致两个键被视为相同
  • Python 3.x:更严格的Unicode处理

安全风险

  • 权限绕过:通过特殊Unicode字符创建"superadmin"等效权限
  • 实验案例:使用superadmin\ud888创建具有管理员权限的用户

2.3 注释处理差异

示例

{
  "description": "Duplicate with comments",
  "test": 2,
  "extra": /*,
  "test": 1,
  "extra2": */
}

不同解析器处理方式:

  • GoJay:忽略注释,保留原始结构
  • JSON-iterator(Java):将注释部分解析为字符串值

2.4 数字类型处理差异

大数处理问题

RFC说明:RFC明确指出大数解析可能存在不一致问题

示例

{
  "qty": 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
}

不同解析器处理方式:

  • Python:保持原值
  • Go:可能解析为0

安全风险

  • 数值校验绕过:大数被解析为0导致业务逻辑错误
  • 实验案例:商品数量使用极大值,后端解析为0导致免费购买

无穷大与NaN处理

RFC说明:官方RFC不支持正负无穷大和NaN

示例

{
  "test": 1.0e4096
}

不同语言处理:

  • PHP0 == "Infinity"返回true,可能导致逻辑绕过

3. JSON序列化风险

不同语言/库在序列化时对重复键的处理不同:

  • JSON-iterator(Java)
    • 内存中:保留第一个值
    • 序列化输出:保留最后一个值
  • rapidjson(C++)
    • 内存中:保留最后一个值
    • 序列化输出:保留所有键值对

4. 防御措施

4.1 对于JSON SDK开发者

  • 严格按照RFC定义规范实现
  • 明确处理边界情况:
    • 重复键
    • 非法Unicode字符
    • 注释
    • 大数和特殊数值

4.2 对于普通开发者(使用方)

  1. 解析器盘点

    • 识别系统中使用的所有JSON解析器
    • 了解它们的特性和差异
  2. 输入验证

    • 使用JSON Schema进行强校验
    • 示例Schema:
      {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "number",
            "maximum": 10
          },
          "cart": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "number",
                  "minimum": 0,
                  "exclusiveMaximum": 9
                },
                "qty": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "required": ["id", "qty"]
            }
          }
        },
        "required": ["orderId", "cart"]
      }
      
  3. 统一解析器

    • 尽量在整个系统中使用相同的JSON解析器
    • 如果必须使用多个解析器,确保它们的行为一致
  4. 安全测试

    • 对JSON处理逻辑进行模糊测试
    • 特别测试边界情况:
      • 重复键
      • 特殊字符
      • 极大/极小数值
      • 非法Unicode

5. 历史相关CVE

历史上许多安全漏洞都源于JSON解析差异,包括但不限于:

  • 权限绕过漏洞
  • 业务逻辑绕过漏洞
  • 数据篡改漏洞

6. 实验复现资源

7. 总结

JSON解析差异可能导致严重的安全问题,特别是在微服务架构中,不同服务可能使用不同的JSON解析器。开发者应当:

  1. 充分了解使用的JSON解析器的特性
  2. 实施严格的输入验证
  3. 在整个系统中保持解析行为的一致性
  4. 对JSON处理逻辑进行全面的安全测试

通过规范JSON处理流程和加强安全防护,可以有效降低因解析差异导致的安全风险。

JSON解析差异与安全风险研究 1. JSON解析差异概述 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,广泛应用于客户端与服务器之间的数据传输。然而,由于缺乏严格的规范定义,不同JSON解析器在处理相同JSON文档时可能存在差异,从而导致潜在的安全风险。 1.1 问题根源 规范不严格 :官方JSON RFC(如8259)对一些细节提供了宽泛的规则 多种解析规范共存 : IETF JSON RFC (8259及之前版本) ECMAScript标准 JSON5(扩展规范,添加注释、无引号字符串等便利功能) HJSON(类似JSON5但有不同设计选择) 2. 主要解析差异类型及安全风险 2.1 重复键处理差异 示例 : 不同解析器处理方式: Python(jsonschema) :以后出现的键值为准(a=2) Go(jsonparser) :以先出现的键值为准(a=1) 安全风险 : 当系统使用多个解析器时(如前端用Go,后端用Python),可能导致业务逻辑绕过 实验案例:利用Python Flask作为代理校验层,Go处理实际计算逻辑,通过重复键绕过校验 2.2 字符截断与Unicode处理差异 示例payload : 不同解析器处理方式: Python 2.x :可能将非法Unicode字符截断,导致两个键被视为相同 Python 3.x :更严格的Unicode处理 安全风险 : 权限绕过:通过特殊Unicode字符创建"superadmin"等效权限 实验案例:使用 superadmin\ud888 创建具有管理员权限的用户 2.3 注释处理差异 示例 : 不同解析器处理方式: GoJay :忽略注释,保留原始结构 JSON-iterator(Java) :将注释部分解析为字符串值 2.4 数字类型处理差异 大数处理问题 RFC说明 :RFC明确指出大数解析可能存在不一致问题 示例 : 不同解析器处理方式: Python :保持原值 Go :可能解析为0 安全风险 : 数值校验绕过:大数被解析为0导致业务逻辑错误 实验案例:商品数量使用极大值,后端解析为0导致免费购买 无穷大与NaN处理 RFC说明 :官方RFC不支持正负无穷大和NaN 示例 : 不同语言处理: PHP : 0 == "Infinity" 返回true,可能导致逻辑绕过 3. JSON序列化风险 不同语言/库在序列化时对重复键的处理不同: JSON-iterator(Java) : 内存中:保留第一个值 序列化输出:保留最后一个值 rapidjson(C++) : 内存中:保留最后一个值 序列化输出:保留所有键值对 4. 防御措施 4.1 对于JSON SDK开发者 严格按照RFC定义规范实现 明确处理边界情况: 重复键 非法Unicode字符 注释 大数和特殊数值 4.2 对于普通开发者(使用方) 解析器盘点 : 识别系统中使用的所有JSON解析器 了解它们的特性和差异 输入验证 : 使用JSON Schema进行强校验 示例Schema: 统一解析器 : 尽量在整个系统中使用相同的JSON解析器 如果必须使用多个解析器,确保它们的行为一致 安全测试 : 对JSON处理逻辑进行模糊测试 特别测试边界情况: 重复键 特殊字符 极大/极小数值 非法Unicode 5. 历史相关CVE 历史上许多安全漏洞都源于JSON解析差异,包括但不限于: 权限绕过漏洞 业务逻辑绕过漏洞 数据篡改漏洞 6. 实验复现资源 BishopFox/json-interop-vuln-labs Lab1: 重复键处理差异利用 Lab2: Unicode字符截断利用 7. 总结 JSON解析差异可能导致严重的安全问题,特别是在微服务架构中,不同服务可能使用不同的JSON解析器。开发者应当: 充分了解使用的JSON解析器的特性 实施严格的输入验证 在整个系统中保持解析行为的一致性 对JSON处理逻辑进行全面的安全测试 通过规范JSON处理流程和加强安全防护,可以有效降低因解析差异导致的安全风险。