原型污染函数¶
ID: js/prototype-pollution-utility
Kind: path-problem
Security severity: 6.1
Severity: warning
Precision: high
Tags:
- security
- external/cwe/cwe-078
- external/cwe/cwe-079
- external/cwe/cwe-094
- external/cwe/cwe-400
- external/cwe/cwe-471
- external/cwe/cwe-915
Query suites:
- javascript-code-scanning.qls
- javascript-security-extended.qls
- javascript-security-and-quality.qls
大多数 JavaScript 对象继承内置 Object.prototype
对象的属性。原型污染是一种攻击者可以修改 Object.prototype
的漏洞类型。由于大多数对象都继承自被篡改的 Object.prototype
,攻击者可以使用它来篡改应用程序逻辑,并经常升级到远程代码执行或跨站脚本攻击。
导致原型污染的一种方法是使用不安全的合并或扩展函数递归地将属性从一个对象复制到另一个对象,或者使用深度赋值函数将属性分配给未经验证的属性名称链。这样的函数有可能修改从目标对象访问到的任何对象,而内置的 Object.prototype
通常可以通过特殊属性 __proto__
和 constructor.prototype
访问。
建议¶
最有效的防御方法是在执行递归复制或深度赋值的函数中。
仅当属性是目标对象的自身属性时,才递归地合并或分配属性。或者,阻止 __proto__
和 constructor
属性被合并或分配。
示例¶
此函数递归地将属性从 src
复制到 dst
。
function merge(dst, src) {
for (let key in src) {
if (!src.hasOwnProperty(key)) continue;
if (isObject(dst[key])) {
merge(dst[key], src[key]);
} else {
dst[key] = src[key];
}
}
}
但是,如果 src
是对象 {"__proto__": {"isAdmin": true}}
,它将在 Object.prototype
中注入属性 isAdmin: true
。
可以通过确保仅递归地合并目标对象的自身属性来修复该问题。
function merge(dst, src) {
for (let key in src) {
if (!src.hasOwnProperty(key)) continue;
if (dst.hasOwnProperty(key) && isObject(dst[key])) {
merge(dst[key], src[key]);
} else {
dst[key] = src[key];
}
}
}
或者,阻止 __proto__
和 constructor
属性
function merge(dst, src) {
for (let key in src) {
if (!src.hasOwnProperty(key)) continue;
if (key === "__proto__" || key === "constructor") continue;
if (isObject(dst[key])) {
merge(dst[key], src[key]);
} else {
dst[key] = src[key];
}
}
}