考虑以下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
吗
我可以安全地将
Object.fromEntries
与未检查的用户提供的数据一起使用吗?
是的,它永远不会通过构建对象来修改Object.prototype
。
我很惊讶
Object.fromEntries
成功创建了一个对象,其.__proto__.toString
被利用,而.toString
没有。
这里.__proto__
没有什么特别之处,它只是Object.prototype
上的getter/setter属性,类似于hasOwnProperty
或isPrototypeOf
。
您会注意到Object.fromEntries
确实构建了一个具有自己的.__proto__
属性的对象,以及x.__proto__ !== Object.prototype
(尽管仍然是Object.getPrototypeOf(x) === Object.prototype
(。继承的属性被隐藏。