快递.js请求正文__proto__

Express.js request body __proto__

本文关键字:proto 正文 请求 js 快递      更新时间:2023-09-26

我对 express.urlencoded() 中间件生成的 request.body 有一点问题。在某些情况下,它会在request.body对象的末尾添加__proto__,而不是像这样直接用于启动moongose模型var user = new User(req.body)

作为一个例子,我将使用node-express-mongoose-demo存储库。所有形式都很好用,但app.post('/users', users.create)会收到 req.body 被__proto__"污染"

提前感谢您的任何帮助

问题似乎来自urlencoded中间件,即包含在Express 3中的中间件。

一个可能的解决方案不是使用 Express bodyParser,而是使用 body-parser 模块。

而不是

app.use(express.urlencoded())

你可以写

var bodyparser = require('body-parser')
..........
app.use(bodyparser.urlencoded())

问题似乎来自qs模块(express 3模块使用的版本)。它强制在其构建的对象上添加__proto__。最新版本没有此问题。

嗯,这很有趣。 __proto__是某些JavaScript实现(包括node/v8)中所有对象的特殊/自动/内部属性。不过,我还没有见过猫鼬做这种事情。此处提供了将传递给模型构造函数的属性转换为模型/文档实例的代码。不过,我没有看到任何可疑的东西。

您是否确切地知道这种情况会发生,并且您确定urlencoded这样做吗?当您尝试保存被此"污染"的用户时会发生什么?通常猫鼬只会忽略架构中未定义的字段,那么会发生什么?

您应该能够(也许?)使用如下所示的中间件解决此问题,但我很好奇真正隔离和了解根本原因。 Underscore/Lodash omit在这里效果很好。

var _ = require('lodash');
function unpollute(req, res, next) {
  req.body = _.omit(req.body, '__proto__');
  next();
}
app.use(express.urlencoded());
app.use(unpollute);

然后,当您的路由处理程序运行时,req.body将不会有__proto__ .

我知道这个问题

问已经 5 年了,但实际上我昨天遇到了同样的问题。

我有好消息要分享 - 看起来猫鼬 5.3.9 实际上解决了这个问题。您可以使用包含 __proto__ 的对象创建新模型。不过,不确定将来是否会持续下去。

此外,qs模块也可以升级到最新版本来解决此问题。

用于测试的代码:

// simulate object creation by express
let newCustomer = Object.create(null);
newCustomer.name = 'new test customer';
newCustomer.__proto__ = Object.prototype;
console.log(newCustomer); // { name: 'new test customer', __proto__: {} }
Customer.create(newCustomer, function(err, created) {
    console.log('err:', err, 'created:', created);
    // mongose 5.3.8: ValidationError: Customer validation failed
    // mongose 5.3.9: new customer created
})

更多细节:

原型有问题,因为 qs 模块使用以下方法创建新对象:

Object.create(null)

然后,当调用restoreProto时,它会尝试修复对象的原型:

obj.__proto__ = Object.prototype;

__proto__最终成为对象的可见属性:

let obj = Object.create(null);
obj.__proto__ = Object.prototype;
console.log(Object.keys(obj));
// [ '__proto__' ]

如果使用 {} 甚至 Object.create(Object) 创建新对象,则__proto__不会出现在键枚举中,即使以相同的方式分配也是如此:

let obj = {};
obj.__proto__ = Object.prototype;
console.log(Object.keys(obj));
// []    

有趣的事实 - 这种行为随着时间的推移而改变。在节点 v0.10.28 中,两个代码片段(好吧,使用 var 而不是 let ;))都会生成空数组。

另一个有趣的事情是,较新版本的qs模块以不同的方式创建对象,因此不再导致此问题。