将 json 天真地解析为 Python class 或结构安全吗?
Is parsing a json naively into a Python class or struct secure?
先介绍一些背景知识:我有一些相当简单的数据结构,它们作为 json 文件保存在磁盘上。这些 json 文件在不同语言和不同环境(如 Web 前端和数据操作工具)的应用程序之间共享。
我想为每个文件创建一个 Python "POPO"(普通旧 Python 对象),并为每个项目创建一个相应的数据映射器 class实现一些类似 CRUD 的简单行为(例如,保存将序列化 class 并在磁盘上存储为 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 的新手。
编辑:感谢大家的评论。我发现我有一个 json,其中有 2 个数组,每个数组都有一张地图。不幸的是,当我得到更多这些时,这看起来会变得很麻烦。
我将问题扩展到将 json 输入映射到记录类型。原始代码来自这里:。
因为我需要可变对象,所以我将其更改为使用命名列表而不是命名元组:
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.
加载后立即添加 validation/conversion
第二个例子有点糟糕。像这样把事情打包成记录对你没有任何帮助。您不继承任何方法,因为您定义的每个类型都是新的。您无法轻松比较值,因为字典没有排序。你不知道你是否处理了所有的参数,或者是否有一些额外的数据,这可能会导致以后隐藏的问题。
总而言之:使用 User(**data)
,您会非常安全。使用 namedlist
有 space 用于歧义,你并没有真正获得任何东西。 (与裸机相比,已解析 json)
如果您盲目地接受用户 json 的输入而不进行完整性检查,您就有成为 json 注入受害者的风险。
在此处查看 json 注入攻击的详细说明:https://www.acunetix.com/blog/web-security-zone/what-are-json-injections/
除了安全漏洞之外,以这种方式将 JSON 解析为 Python 对象是类型不安全的。
以您的用户 class 为例,我假设您希望字段 name
和 username
都是字符串类型。如果 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/
先介绍一些背景知识:我有一些相当简单的数据结构,它们作为 json 文件保存在磁盘上。这些 json 文件在不同语言和不同环境(如 Web 前端和数据操作工具)的应用程序之间共享。
我想为每个文件创建一个 Python "POPO"(普通旧 Python 对象),并为每个项目创建一个相应的数据映射器 class实现一些类似 CRUD 的简单行为(例如,保存将序列化 class 并在磁盘上存储为 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 的新手。
编辑:感谢大家的评论。我发现我有一个 json,其中有 2 个数组,每个数组都有一张地图。不幸的是,当我得到更多这些时,这看起来会变得很麻烦。
我将问题扩展到将 json 输入映射到记录类型。原始代码来自这里:。 因为我需要可变对象,所以我将其更改为使用命名列表而不是命名元组:
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.
加载后立即添加 validation/conversion第二个例子有点糟糕。像这样把事情打包成记录对你没有任何帮助。您不继承任何方法,因为您定义的每个类型都是新的。您无法轻松比较值,因为字典没有排序。你不知道你是否处理了所有的参数,或者是否有一些额外的数据,这可能会导致以后隐藏的问题。
总而言之:使用 User(**data)
,您会非常安全。使用 namedlist
有 space 用于歧义,你并没有真正获得任何东西。 (与裸机相比,已解析 json)
如果您盲目地接受用户 json 的输入而不进行完整性检查,您就有成为 json 注入受害者的风险。
在此处查看 json 注入攻击的详细说明:https://www.acunetix.com/blog/web-security-zone/what-are-json-injections/
除了安全漏洞之外,以这种方式将 JSON 解析为 Python 对象是类型不安全的。
以您的用户 class 为例,我假设您希望字段 name
和 username
都是字符串类型。如果 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/