FlawOpen

flawopen.com/JSON 解析/JSON.parse() vs eval()

JSON.parse() 比 eval() 更安全吗?

参考指南
简答

把输入想成一张便条:JSON.parse()读取结构化表单中的字段,而eval()会把便条交给解释器当作要执行的指令。JSON.parse()遵循JSON语法,不会执行文本中的JavaScript;使用解析结果前仍需验证这些值。

危险 — 旧式写法
// 不要把不可信数据当作程序源代码执行。
const data = eval("(" + untrustedJson + ")");
安全
const data = JSON.parse(untrustedJson);
// 将 JSON 作为数据解析;无效 JSON 会抛出 SyntaxError。

为什么会有这个问题

在 JSON.parse() 普及之前,一些旧 JavaScript 代码会用 eval() 读取 JSON,因为 JSON 文本与 JavaScript 表达式语法有重叠。这种做法会求值执行 JavaScript 程序,因此攻击者控制的输入可能被当作代码,而不是受 JSON 值语法约束的数据。解析 JSON 应使用 JSON 解析器。

JSON.parse() 仍无法保护什么

JSON.parse() 不会验证业务规则、授权操作,也不会自动让解析出的值适用于 HTML、SQL、Shell 命令或 URL。请验证预期的数据结构,并使用适合上下文的输出编码或参数化 API。如果传入 reviver,应用提供的回调会在解析过程中运行;应确保它可信、简单,且不会根据攻击者控制的值产生副作用。

常见问题

JSON.parse() 会执行应用代码吗?

JSON 文本本身会作为数据解析,不会作为 JavaScript 执行。不过,如果应用提供 reviver,解析时会为各个值调用这个可信回调,而回调可以运行代码。不要让攻击者控制的数据选择或构造可执行的回调逻辑。

JSON.parse() 会让输入在后续使用时安全吗?

不会。请根据应用预期的结构和授权规则检查解析后的值。HTML 使用输出编码,SQL 使用参数化查询;解析本身不会针对这些上下文净化数据。

参考资料

另请参阅 JavaScript 原型污染:成因与防护 lodash.merge() 能防止原型污染吗? Object.assign() 与原型污染:哪些用法安全? JSON.parse() 会导致原型污染吗?