未验证的动态方法调用¶
ID: js/unvalidated-dynamic-method-call
Kind: path-problem
Security severity: 7.5
Severity: warning
Precision: high
Tags:
- security
- external/cwe/cwe-754
Query suites:
- javascript-code-scanning.qls
- javascript-security-extended.qls
- javascript-security-and-quality.qls
JavaScript 使得在运行时动态查找对象属性变得容易。特别是,方法可以通过名称查找,然后调用。但是,如果方法名由用户控制,攻击者可以选择一个名称,使应用程序调用意外的方法,这可能会导致运行时异常。如果此异常未被处理,它可能被用于发动拒绝服务攻击。
例如,可能不存在给定名称的方法,或者查找的结果可能不是函数。在这两种情况下,方法调用都会在运行时抛出 TypeError
。
另一个更微妙的例子是,查找的结果是来自 Object.prototype
的标准库方法,大多数对象在其原型链上都有此方法。此类方法的例子包括 valueOf
、hasOwnProperty
和 __defineSetter__
。如果方法调用向这些方法传递了错误的数量或类型的参数,它们将抛出异常。
建议¶
最好完全避免涉及用户控制名称的动态方法查找,例如使用 Map
而不是普通对象。
如果无法避免动态方法查找,请考虑将允许的方法名列入白名单。至少,请检查方法是否为自身属性,而不是从原型对象继承的属性。如果查找方法的对象包含不是方法的属性,则应额外检查查找结果是否为函数。即使对象只包含方法,在以后向对象添加其他属性的情况下,执行此检查仍然是一个好主意。
示例¶
在以下示例中,HTTP 请求参数 action
属性用于在 actions
映射中动态查找函数,然后用 payload
参数作为其参数来调用该函数。
var express = require('express');
var app = express();
var actions = {
play(data) {
// ...
},
pause(data) {
// ...
}
}
app.get('/perform/:action/:payload', function(req, res) {
let action = actions[req.params.action];
// BAD: `action` may not be a function
res.end(action(req.params.payload));
});
目的是允许客户端调用 play
或 pause
方法,但没有检查 action
是否实际上是存储在 actions
中的方法的名称。例如,如果 action
是 rewind
,则 action
将为 undefined
,并且调用将导致运行时错误。
防止这种情况最简单的方法是将 actions
变成 Map
,并使用 Map.prototype.has
检查方法名在查找之前是否有效。
var express = require('express');
var app = express();
var actions = new Map();
actions.set("play", function play(data) {
// ...
});
actions.set("pause", function pause(data) {
// ...
});
app.get('/perform/:action/:payload', function(req, res) {
if (actions.has(req.params.action)) {
if (typeof actions.get(req.params.action) === 'function'){
let action = actions.get(req.params.action);
}
// GOOD: `action` is either the `play` or the `pause` function from above
res.end(action(req.params.payload));
} else {
res.end("Unsupported action.");
}
});
如果 actions
不能变成 Map
,则应添加 hasOwnProperty
检查以验证方法名
var express = require('express');
var app = express();
var actions = {
play(data) {
// ...
},
pause(data) {
// ...
}
}
app.get('/perform/:action/:payload', function(req, res) {
if (actions.hasOwnProperty(req.params.action)) {
let action = actions[req.params.action];
if (typeof action === 'function') {
// GOOD: `action` is an own method of `actions`
res.end(action(req.params.payload));
return;
}
}
res.end("Unsupported action.");
});
参考¶
OWASP: 拒绝服务.
MDN: Map。
MDN: Object.prototype。
通用弱点枚举:CWE-754。