给定一个用户提供的JSON字符串,我们如何在运行JSON.parse(untrustedString)
之前清理它?
我主要担心的是原型污染,但我也想知道我还应该注意什么?如果只是原型污染是一个风险,那么我假设可以通过正则表达式处理,但我怀疑还有其他问题?
例如,this article on the dangers of parsing untrusted JSON and then creating a copy of the object.:
现在考虑发送到该端点的一些恶意JSON数据。
{
"user": {
"__proto__": {
"admin": true
}
}
}
如果这个JSON被发送,JSON.parse
将生成一个带有__proto__
属性的对象。如果复制库按上述方式工作,它将把admin属性复制到req.session.user
的原型上!
3条答案
按热度按时间5lhxktic1#
我主要关心的是原型污染
请注意,
JSON.parse
不会污染任何原型对象。如果JSON字符串有一个"__proto__"
键,那么该键将像任何其他键一样被创建,无论对应的值在JSON中是什么,它最终都会作为该属性值,而不是在原型对象(Object.prototype
)中。风险在于你在 * 之后 * 对那个对象做了什么。如果你使用属性赋值或
Object.assign
执行(深度)复制,* 那么 * 你可能会改变原型对象。我们如何在运行
JSON.parse(untrustedString)
之前清理它?...我假设可以通过regex处理不要使用正则表达式。使用
JSON.parse
的第二个参数:nfzehxib2#
在你对它做任何事情之前,
userString
只是一个字符串,这个字符串本身没有任何东西可以伤害系统,除非系统做了一些允许这种伤害的事情,比如以不安全的方式处理它。输入
JSON.parse()
。JSON.parse()
是一个简单的格式转换工具。它不运行数据中的任何方法(proto pollution profits依赖),甚至不需要“查看”字符串化对象本身包含的数据,除了structural syntax it contains和JavaScript保留字,以用于验证目的(MDN polyfill示例)。这里的原理和弦一样适用;如果你不对输出对象做任何不安全的事情,它就不会伤害你或你的系统。最终,防止滥用可以简单地归结为验证和安全数据处理实践:
Object.prototype.hasOwnProperty.call()
。使用eslint(no-prototype-builtins rule)等工具在代码库中执行这些实践。在article you linked中,作者提到了这个确切的想法:
...来自用户的数据应始终进行过滤和清理。
mdfafbf13#
也许最重要的是简单地限制大小。内存溢出可能会超出应用程序沙箱的范围。
下一个最重要的事情是关注你自己的角色集,并清理你不打算工作的东西。
如果您不期望完全支持Unicode,那么明确地不支持它(在处理转义之后,过滤到更简单的代码,如ASCII),因为代码很复杂,会碰到可能被破坏的二进制层
最后,有一个明确的键列表,您支持并验证每个键中的值,这样您就不必担心应用程序逻辑出错。