如何从JSON对象中删除__proto__属性?

6

我有一个基于Node-Express的函数:

//function on server side
app.get('/loginCheck', loggedCheck, function(req, res) {
    var data = {local: {}, facebook: {}};
    data.id = req.user._id;
    data.local.email = req.user.local.email;
    data.local.fname = req.user.local.fname;
    data.local.lname = req.user.local.lname ;
    data.local.college = req.user.local.college ;
    data.local.degree = req.user.local.degree ;
    data.year = req.user.year ;
    data.mobile = req.user.mobile ;
    data.city = req.user.city ;
    data.facebook.id = req.user.facebook.id ;
    //res.json(data);        

    var x = {};
    x.name = "someName"

    res.json(x);
})

以下是客户端代码,用于发起Ajax请求:
//function on client side making an ajax request
$.get("/loginCheck",function(data,status){
    console.log(data);
});

在服务器端的旧代码中,req.user是由mongoose创建的mongodb对象。我想做的是将数据对象(其中包含req.user对象的一些选定属性)发送并作为JSON响应发送。
变量x是一个自定义创建的变量。
问题是: 当我将data对象发送到客户端时,也会添加__proto__属性,而当我将x发送到客户端时不会发生这种情况。 但是,我不希望在客户端上有__proto__,因为从一些文章中我发现__proto__存在安全问题。
我需要帮助删除data对象中的__proto__

您无法删除__proto__,它是一个内部属性。 - Bhojendra Rauniyar
2
@BhojendraSah:.__proto__不是内部属性,而是从Object.prototype继承的一个属性。 - Bergi
1
安全问题?不,你一定看错了。你能指出那些文章吗? - Bergi
2
res.json 不会包含 __proto__ 属性。你确定在实际的 HTTP 响应中看到了它吗? - JohnnyHK
4个回答

5

如果您使用Object.create(null)并定义要使用的属性,可以简单地放弃对象上的原型。

var obj = Object.create(null);

Object.defineProperty(obj, {
  'foo': {
    value: 1,
    enumerable: true,

  },
  'bar': {
    value: 2,
    enumerable: false
  }
});

// or...

obj.foo = 1
obj.bar = 2

/* various checks */

obj instanceof Object; // false
Object.prototype.isPrototypeOf(obj); // false
Object.getPrototypeOf(obj); // null
obj + ""; // TypeError: Cannot convert object to primitive value
'toString' in obj; // false
foo; // 1
obj['bar']; // 2
JSON.stringify(obj); // {"foo":1}
{}.hasOwnProperty.call(obj, 'foo'); // true
{}.propertyIsEnumerable.call(obj, 'bar'); // false

在这种方法中,您不再需要检查obj.hasOwnProperty(key)
for (var key in obj) {
  // do something
}

阅读更多:JavaScript中真正的哈希表

MDN: Object.defineProperty()Object.create()

// with __proto__

var obj = {} // equivalent to Object.create(Object.prototype);
obj.key = 'value'

console.log(obj)



// without __proto__

var bareObj = Object.create(null)
Object.defineProperty(bareObj, {
  'key': {
    value: 'value',
    enumerable: false,
    configurable: true,
    writable: true
  }
})
// or... bareObj.key = 'value'

console.log(bareObj)


OP似乎正在发送和解析JSON,这并不是你真正的选择。而且我们中没有人能够重现这个问题。 - Bergi
OP可以将他的JSON映射到裸对象,然后解析它:Object.keys(obj).map(key => bareObj[key] = obj[key]) 或者 Object.assign(bareObj, obj)。不过,这种方法已经有些老了,但是我想展示它可以为其他遇到类似问题的人提供帮助。 - darcher
这并不阻止 __proto__ 在赋值时调用特殊行为。无论被赋值的内容以前是否有原型,都会将其设置为原型。 - jgmjgm
同意@jgmjgm的观点。虽然创建自己的对象似乎不错,但这仍然无法解决反序列化对象时遇到的问题,特别是如果您正在反序列化传递给eval的函数-请参见此处 - npetrov937

2

发送__proto__可能会创建一个JSON对象,如果将键转移到另一个对象而不删除__proto__,可能会破坏事物或泄露敏感数据。

通常,它不会出现在编码的JSON中,这很不寻常。这表明可能存在其他问题或临时解决方案。您使用的库可能会意外泄漏它或利用它。在封闭系统中使用它可能是可以的,但不应允许其进入或离开系统。

// If is optional.
if('__proto__' in obj)
    // This may cause unintended consequences.
    delete(obj.__proto__);

在接收数据时,您还应非常小心,确保它不包含__proto__属性。如果该键被复制到另一个对象中,则可能会导致服务器崩溃或受到威胁。

如果创建自己的对象,可以使用defineProperty等技巧来更改其行为,但这些技巧往往不能完全消除问题。


似乎 delete obj.__proto__ 并没有真正将其删除。 - mpen

2
您无需删除此内容,它不会造成任何麻烦或问题。 您可以像这样使用。
$.each(data, function(k, v) {
    console.log(k, v);
});

0

只需编写

String(<在此处输入您的数据>)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接