`Object.fromEntries()` 是否可以避免原型污染?

Is `Object.fromEntries()` secure from prototype pollution?

考虑以下 JavaScript 中原型污染的简单示例:

function sayHello(name) {
  console.log(`Hi ${name}!`);
}

// Pollute the prototype
({}).__proto__.toString = () => alert('hacked');

// Trigger the exploit
sayHello({});

我想知道是否可以用 Object.fromEntries 完成类似的利用,所以我测试了:

function sayHello(name) {
  console.log(`Hi ${name}!`);
}

// Try to pollute the prototype, but doesn't work, even for the same object!
const x = Object.fromEntries([['__proto__', { toString: () => alert('hacked') }]]);

// Try to trigger the exploit, but fail
sayHello({}); // Hi [object Object]
sayHello(x); // Hi [object Object]

内置 Object.fromEntries 不受此漏洞利用这一事实非常好,我期待一些保护。但是,我认为它会抛出错误或跳过设置 __proto__,但令我惊讶的是 __proto__ 实际上已设置!

x.__proto__.toString(); // Exploited!
x.toString(); // Not exploited!!

令我感到非常惊讶的是 Object.fromEntries 设法创建了一个 .__proto__.toString 被利用而 .toString 没有被利用的对象。

那么,这样安全吗?

我可以安全地使用 Object.fromEntries 未经检查的用户提供的数据吗?

Can I use Object.fromEntries with unchecked user-supplied data safely?

是的,它永远不会通过构建对象来修改Object.prototype

I was very surprised that Object.fromEntries managed to create an object whose .__proto__.toString is exploited while .toString is not.

这里的.__proto__没有什么特别的,只是Object.prototype上的getter/setter属性,类似于hasOwnPropertyisPrototypeOf

您会注意到 Object.fromEntries 确实构建了一个具有 own .__proto__ 属性 的对象,并且 x.__proto__ !== Object.prototype (尽管仍然 Object.getPrototypeOf(x) === Object.prototype)。继承的属性被遮蔽了