CodeQL 文档

原型污染函数

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

点击查看 CodeQL 代码库中的查询

大多数 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];
        }
    }
}

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私