CodeQL 文档

未验证的动态方法调用

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

点击查看 CodeQL 仓库中的查询

JavaScript 使得在运行时动态查找对象属性变得容易。特别是,方法可以通过名称查找,然后调用。但是,如果方法名由用户控制,攻击者可以选择一个名称,使应用程序调用意外的方法,这可能会导致运行时异常。如果此异常未被处理,它可能被用于发动拒绝服务攻击。

例如,可能不存在给定名称的方法,或者查找的结果可能不是函数。在这两种情况下,方法调用都会在运行时抛出 TypeError

另一个更微妙的例子是,查找的结果是来自 Object.prototype 的标准库方法,大多数对象在其原型链上都有此方法。此类方法的例子包括 valueOfhasOwnProperty__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));
});

目的是允许客户端调用 playpause 方法,但没有检查 action 是否实际上是存储在 actions 中的方法的名称。例如,如果 actionrewind,则 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.");
});

参考

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