【问题标题】:Is parsing a json naively into a Python class or struct secure?将 json 天真地解析为 Python 类或结构是否安全?
【发布时间】:2015-07-05 22:53:28
【问题描述】:

首先了解一些背景知识:我有一些相当简单的数据结构,它们作为 json 文件保存在磁盘上。这些 json 文件在不同语言和不同环境的应用程序(如 Web 前端和数据操作工具)之间共享。

对于每个文件,我想创建一个 Python“POPO”(普通旧 Python 对象),并且每个项目的相应数据映射器类应该实现一些简单的 CRUD 类行为(例如,save 将序列化类并存储为json 文件在磁​​盘上)。

我认为一个简单的映射器(只知道基本类型)会起作用。但是,我担心安全性。一些 json 文件将由 Web 前端生成,因此如果用户向我提供一些错误的 json,可能会带来安全风险。

最后,这是简单的映射代码(位于How to convert JSON data into a Python object):

class User(object):
def __init__(self, name, username):
    self.name = name
    self.username = username

import json
j = json.loads(your_json)
u = User(**j)

您发现了哪些可能的安全问题?

注意:我是 Python 新手。

编辑:感谢大家的cmets。我发现我有一个 json,其中有 2 个数组,每个数组都有一张地图。不幸的是,当我得到更多这些时,这开始看起来很麻烦。

我将问题扩展到将 json 输入映射到记录类型。原始代码来自这里:https://stackoverflow.com/a/15882054/1708349。 由于我需要可变对象,因此我将其更改为使用命名列表而不是命名元组:

import json
from namedlist import namedlist

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: namedlist('X', d.keys())(*d.values()))
print x.name, x.hometown.name, x.hometown.id

还安全吗?

【问题讨论】:

  • 我能想到的唯一问题是,由于加载了无效数据,某些东西会中断。
  • json 只能解析有限的类型,int、bool 等。不会执行任何操作,所以我看不到任何真正的安全风险
  • 我仍然会对来自 Web 服务的输入进行一些健全性检查,尤其是当这些对象要访问数据库时。可能类似于将name 限制为 100 个可打印字符并且不允许使用一些标点符号(如分号)。看到这个帖子stackoverflow.com/questions/421046/…

标签: python json datamapper


【解决方案1】:

在第一种情况下不会发生太多错误。您正在限制可以提供的参数,并且很容易在从 JSON 加载后立即添加验证/转换。

第二个例子有点糟糕。像这样将内容打包到记录中对您没有任何帮助。您不继承任何方法,因为您定义的每种类型都是新的。您无法轻松比较值,因为 dicts 没有排序。你不知道你是否处理了所有参数,或者是否有一些额外的数据,这可能会导致以后隐藏的问题。

总而言之:使用User(**data),您非常安全。使用namedlist 存在模棱两可的空间,您并没有真正获得任何东西。 (与裸露的、解析过的 json 相比)

【讨论】:

    【解决方案2】:

    如果你在没有完整性检查的情况下盲目接受用户的 json 输入,你就有成为 json 注入受害者的风险。

    json注入攻击的详细解释看这里:https://www.acunetix.com/blog/web-security-zone/what-are-json-injections/

    除了安全漏洞之外,以这种方式将 JSON 解析为 Python 对象不是类型安全的。

    对于您的 User 类示例,我假设您希望两个字段 nameusername 都是字符串类型。如果json输入是这样的:

    {
      "name": "my name",
      "username": 1
    }
    
    j = json.loads(your_json)
    u = User(**j)
    
    type(u.username) # int
    

    你得到了一个意外类型的对象。

    确保类型安全的一种解决方案是使用 json 模式来验证输入 json。更多关于 json 架构的信息:https://json-schema.org/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-27
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多