给定一个用户提供的JSON字符串,我们如何在运行JSON.parse(untrustedString)
之前对其进行清理?
我最关心的是原型污染,但我也想知道我还应该注意什么?如果只是原型污染是一种风险,那么我认为可以通过regex处理,但我怀疑还有其他问题吗?
例如,本文介绍了解析不受信任的JSON然后创建对象副本的危险
现在考虑一些发送到此端点的恶意JSON数据。
{ "user": { "__proto__": { "admin": true } } }
如果发送此JSON,
JSON.parse
将生成一个具有__proto__
属性。如果复制库如上所述工作,它将把admin属性复制到的原型上req.session.user
!
我主要关心的是原型污染
请注意,JSON.parse
不会污染任何原型对象。如果JSON字符串有一个"__proto__"
键,那么该键将像创建任何其他键一样创建,无论该JSON中的相应值是什么,它最终都将作为该属性值,而不是在原型对象(Object.prototype
(中。
风险在于您在之后对该对象所做的操作。如果使用属性赋值或Object.assign
执行(深度(复制,则可能会使原型对象发生变异。
如何在运行
JSON.parse(untrustedString)
之前对其进行消毒。。。我认为这可以通过regex 处理
不要为此使用正则表达式。使用JSON.parse
:的第二个参数
const cleaner = (key, value) => key === "__proto__" ? undefined : value;
// demo
let json = '{"user":{"__proto__":{"admin": true}}}';
console.log(JSON.parse(json));
console.log(JSON.parse(json, cleaner));
在使用它之前,userString
只是一个字符串,该字符串中的任何内容本身都不会对系统造成伤害,除非系统采取了允许这种伤害的措施,比如以不安全的方式处理它。
输入JSON.parse()
。
JSON.parse()
只是一个简单的格式转换工具。它不从数据中运行任何方法(原始污染利用依赖于这些数据(,甚至不从字符串化对象本身中包含的数据中查看,除了它包含的结构语法和JavaScript保留字之外,用于验证目的(MDN polyfill示例(。这里适用的原理与字符串相同;如果你没有对输出对象做任何不安全的事情,它不会伤害你或你的系统。
归根结底,防止滥用可以归结为验证和安全数据处理实践:
-
检查解析字符串得到的对象,并验证它在严格的参数范围内,忽略原型突变。
-
使用
Object.prototype.hasOwnProperty.call()
。强制执行这些使用esint等工具在代码库中进行实践(没有原型内置规则(。 -
不要期望用户发送完美、安全的数据。
在你链接的文章中,作者提到了这个确切的想法:
。。。应该始终对来自用户的数据进行过滤和净化
可能最重要的是简单地限制大小。内存溢出可能超出应用程序沙箱的范围。
其次最重要的是关注自己的角色设置,并清理那些你不会处理的东西。
如果你不希望完全支持Unicode,那么明确地不支持它(在处理转义后,过滤到更简单的东西,如ASCII(,因为该代码很复杂,并且会碰到可能损坏的二进制层
最后,有一个明确的键列表,您支持并验证每个键中的值,这样您就不必担心应用程序逻辑会出错。