远程属性注入¶
ID: js/remote-property-injection
Kind: path-problem
Security severity: 7.5
Severity: warning
Precision: medium
Tags:
- security
- external/cwe/cwe-250
- external/cwe/cwe-400
Query suites:
- javascript-security-extended.qls
- javascript-security-and-quality.qls
从不受信任的输入动态计算对象属性名称可能会有多个不希望的结果。例如,如果属性访问用作写入的一部分,攻击者可能会覆盖对象的至关重要的属性,例如__proto__
。这种攻击被称为原型污染攻击,可以作为拒绝服务攻击的载体。类似的攻击向量是使用原始值替换对象的toString
属性。然后,无论何时显式或隐式地(作为类型强制转换的一部分)调用该对象的toString
,都会引发异常。
此外,如果 HTTP 标头的名称受用户控制,攻击者可能会利用这一点覆盖安全关键的标头,例如Access-Control-Allow-Origin
或Content-Security-Policy
。
建议¶
原型污染漏洞出现的最常见情况是,当 JavaScript 对象用于实现映射数据结构时。应尽可能避免这种情况,而应使用 ECMAScript 2015 的Map
。如果不可能,另一种修复方法是在使用不受信任的输入进行属性访问之前,在其前面加上一个标记字符,例如$
。这样一来,攻击者将无法访问不以选定字符开头的内置属性。
当使用用户输入作为标头名称的一部分时,应对输入进行清理,以确保该名称不会与现有的标头名称冲突,例如Content-Security-Policy
。
示例¶
在下面的示例中,动态计算的属性prop
通过使用用户控制的值来访问myObj
。
var express = require('express');
var app = express();
var myObj = {}
app.get('/user/:id', function(req, res) {
var prop = req.query.userControlled; // BAD
myObj[prop] = function() {};
console.log("Request object " + myObj);
});
这是不安全的,因为攻击者可能会利用此代码将__proto__
属性覆盖为空函数。如果发生这种情况,console.log
参数中的串联将失败,并显示一条令人困惑的消息,例如“Function.prototype.toString 不是泛型”。如果应用程序没有正确处理此错误,这种情况可能会导致严重的拒绝服务攻击。修复方法是在用户控制的字符串前面加上一个标记字符,例如$
,这将阻止覆盖任意属性名称。
var express = require('express');
var app = express();
var myObj = {}
app.get('/user/:id', function(req, res) {
var prop = "$" + req.query.userControlled; // GOOD
myObj[prop] = function() {};
console.log("Request object " + myObj);
});