防范原型链污染漏洞
翻译
原文:https://portswigger.net/web-security/prototype-pollution/preventing
- name: 翻译
desc: 原文:https://portswigger.net/web-security/prototype-pollution/preventing
bgColor: '#F0DFB1'
textColor: 'green'
2
3
4
# 1防范原型链污染漏洞
我们建议你修补所发现的任何原型链污染漏洞,无论这些漏洞是否能够被利用。即使你确信,自己没有遗漏任何一个漏洞,也不能保证未来编写的代码 或 依赖库的更新不会引入新的小工具,从而为可行的漏洞利用铺平道路。
在本节中,我们将提供一些高级建议,说明你可以采取的一些措施,以保护你自己的网站免受我们在实验室中介绍的威胁。我们还将介绍一些需要避开的常见陷阱。
# 2清理属性键
防止原型链污染漏洞的一个常见方法,在将属性键合并到现有对象之前,对其进行清理。这样,你就可以防止攻击者注入__proto__
这一类用于引用对象原型的键。
执行此操作的最有效方法 - 使用允许键的白名单列表。但是,这在许多情况下是不可行的,因此通常会改为使用黑名单列表,从用户输入中删除任何具有潜在危险的字符串。
虽然这是一个快速解决方案,但真正强大的黑名单列表实际上都是棘手的,正如阻止了__proto__
的网站那样,他们没有考虑到攻击者还可以通过构造函数来污染对象的原型 (opens new window)。同样,脆弱的实现也会被简单的混淆技术绕过 (opens new window)。出于这个原因,我们建议只将该防御方法作为一种权宜之计,而不是长期解决方案。
# 3避免对原型对象执行更改
防止原型链污染漏洞的更可靠方法,完全禁止原型对象的更改操作。
在对象上调用Object.freeze()
方法之后,可以确保其属性和值不能再被修改,同时也不能再添加新属性。由于原型本身只是一个对象,因此你可以使用此方法,主动切断任何潜在的污染源:
Object.freeze(Object.prototype);
另外,Object.seal()
方法与此类似,但仍然允许更改现有的属性值。如果你出于任何原因导致不能使用Object.freeze()
,这可能是一个很好的折中方案。
# 4阻止对象继承属性
虽然你可以使用Object.freeze()
来阻止潜在的原型污染源,但同时,你还可以采取额外的措施来消除小工具。这样,即使攻击者识别到了原型链污染漏洞,也大概率无法利用它。
默认情况下,所有的对象都会通过原型链,直接或间接地从全局Object.prototype
上继承属性。但是,你也可以通过Object.create()
方法来创建对象,同时手动设置该对象的原型。这不仅可以让你指定 任何你喜欢的新原型,还可以传递一个null
原型来创建对象,从而确保新对象根本不会继承任何属性。
let myObject = Object.create(null);
Object.getPrototypeOf(myObject); // null
2
# 5尽可能使用更安全的替代品
另一个针对原型链污染的强大防御措施,使用内置的受保护对象。例如,在定义 options 对象时可以改为使用Map
(映射)。尽管 map 仍然可能继承恶意属性,但它们有一个内置的get()
方法,该方法只会返回当前 map 自身拥有的属性:
Object.prototype.evil = 'polluted';
let options = new Map();
options.set('transport_url', 'https://normal-website.com');
options.evil; // 'polluted'
options.get('evil'); // undefined
options.get('transport_url'); // 'https://normal-website.com'
2
3
4
5
6
7
如果你只是单纯地想存储 “值” 而不是key:value
对,则Set
(集合)是另一种选择。就像 map 一样,set 也提供了内置方法,这些方法只会返回当前 set 自身拥有的属性:
Object.prototype.evil = 'polluted';
let options = new Set();
options.add('safe');
options.evil; // 'polluted';
options.has('evil'); // false
options.has('safe'); // true
2
3
4
5
6
7