3

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

作为示例,我将使用node-express-mongoose-demo存储库。所有表格都可以正常工作,但app.post('/users', users.create)收到 req.body “污染”__proto__

提前感谢您的帮助

4

3 回答 3

2

似乎问题出在urlencoded中间件上,它包含在Express 3.

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

代替

app.use(express.urlencoded())

你可以写

var bodyparser = require('body-parser')

..........

app.use(bodyparser.urlencoded())

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

于 2016-01-27T19:50:57.113 回答
0

嗯,这很有趣。__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__.

于 2013-11-04T20:35:00.033 回答
0

我知道这个问题被问到现在已经 5 年了,但实际上我昨天遇到了同样的问题。

我有好消息要分享 - 看起来mongoose 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 模块以不同的方式创建对象,因此它不再导致此问题。

于 2018-11-03T21:52:06.907 回答