表达.js我们应该对body有多怀疑?



https://expressjs.com/en/4x/api.html 状态

由于 req.body 的形状基于用户控制的输入,因此此对象中的所有属性和值都是不受信任的,应在信任之前进行验证。例如,req.body.foo.toString() 可能以多种方式失败,例如 foo 可能不存在或可能不是字符串,而 toString 可能不是一个函数,而是一个字符串或其他用户输入。

我想我在原型污染读取 https://github.com/expressjs/body-parser/issues/347 和 https://learn.snyk.io/lessons/prototype-pollution/javascript/的背景下(在有限的程度上)理解了这一点(不要对可能污染原型或构造函数的未经验证的对象执行某些操作)

我认为如果不执行这样的操作(Snyk 示例中的合并函数),req.body.foo.toString() 本身不能立即包含远程/用户提供的代码?(也就是说,toString() 函数是完全任意的?)。

还是我误解了,在安全地调用其 toString() 之前,有必要在 req.body.foo 上检查变量是否是 JavaScript 中的字符串?

非常感谢

Express 将不允许自定义代码潜入req.body。 因此,您不必担心方法中的恶意代码.toString()位于特定属性上,但req.body中的对象可能具有一个名为.toString的自定义属性,该属性具有值(代码以外的内容),如learn.snky.io示例中所示。

请记住,Express 中的req.body来自解析传入请求的正文。 该正文将根据内容类型进行编码。 最常见的是,它将是applications/jsonapplication/x-www-form-urlencoded的,并且这些编码都无法让发送者包含Javascript代码,这些代码将成为实时代码作为解码的一部分。 因此,这些内容类型不受实时代码注入的影响。 现在,属性中可能有字符串形式的代码,但它不会是实时的或执行的,除非您在如何使用该数据时执行不正确的操作(例如对其调用eval())。

而且,您不一定知道给定属性在req.body上的类型。 您可能期望客户端发送属性值的字符串,但它可能会发送数字或对象(两者都具有不同的.toString()实现)。

如果希望该值为字符串,则可以通过选中if (typeof req.body.foo === "string")来验证它是否为字符串,如果它是字符串,则无需对其调用.toString(),因为它已经是字符串。

对服务器的强大保护将在尝试使用它之前验证您打算在req.body中使用的每个传入属性的类型,并且在如何将信息从req.body复制到其他对象时将非常小心,因为如果您使用错误的复制方法,您可能会产生原型污染。 而且,为了避免任何时髦的方法替换可能在req.body中的对象上,您可以将单个属性复制到一个新对象并在那里使用它。

我的安全而简单的规则是首先检查类型并验证我想要使用的任何属性的值,然后仅将单个命名属性从req.body复制到我自己的对象。 我从不使用递归复制所有属性的函数复制整个对象。 这就是你如何变得容易受到原型污染的影响,通过盲目地从req.body复制那些不是你所期望的已知属性的东西。

如果我想将 10 个属性复制到另一个对象,我将创建一个包含 10 个属性名称的数组,并使用循环单独复制这 10 个命名属性,留下任何其他潜在的恶意属性(例如我不想要的__proto__)。 如果我只使用几个属性,我只需手动将它们分配给我创建的新对象。 我不会使用像Object.assign()这样的东西从req.body批量复制,因为这可以并且会复制我不希望污染我自己的编程对象的东西。

最新更新