CodeQL 文档

服务器端 URL 重定向

ID: js/server-side-unvalidated-url-redirection
Kind: path-problem
Security severity: 6.1
Severity: warning
Precision: high
Tags:
   - security
   - external/cwe/cwe-601
Query suites:
   - javascript-code-scanning.qls
   - javascript-security-extended.qls
   - javascript-security-and-quality.qls

点击查看 CodeQL 仓库中的查询

在没有验证输入的情况下直接将用户输入合并到 URL 重定向请求中会助长网络钓鱼攻击。在这些攻击中,毫无戒心的用户可能会被重定向到一个恶意网站,该网站看起来与他们打算访问的真实网站非常相似,但实际上由攻击者控制。

建议

为了防止不可信的 URL 重定向,建议避免将用户输入直接放入重定向 URL 中。相反,在服务器上维护一个授权重定向列表;然后根据提供的用户输入从该列表中进行选择。

如果这不可行,那么应该通过其他方式验证用户输入,例如验证目标 URL 是否与当前页面的主机相同。

示例

以下示例显示了一个 HTTP 请求参数在没有验证输入的情况下直接用于 URL 重定向,这会助长网络钓鱼攻击

const app = require("express")();

app.get("/redirect", function (req, res) {
  // BAD: a request parameter is incorporated without validation into a URL redirect
  res.redirect(req.query["target"]);
});

解决此问题的一种方法是在执行重定向之前,根据已知的固定字符串验证用户输入

const app = require("express")();

const VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html";

app.get("/redirect", function (req, res) {
  // GOOD: the request parameter is validated against a known fixed string
  let target = req.query["target"];
  if (VALID_REDIRECT === target) {
    res.redirect(target);
  } else {
    res.redirect("/");
  }
});

或者,我们可以通过解析它相对于具有已知主机的基本 URL 并验证主机是否保持不变来检查目标 URL 是否没有重定向到其他主机

const app = require("express")();

function isLocalUrl(path) {
  try {
    return (
      // TODO: consider substituting your own domain for example.com
      new URL(path, "https://example.com").origin === "https://example.com"
    );
  } catch (e) {
    return false;
  }
}

app.get("/redirect", function (req, res) {
  // GOOD: check that we don't redirect to a different host
  let target = req.query["target"];
  if (isLocalUrl(target)) {
    res.redirect(target);
  } else {
    res.redirect("/");
  }
});

请注意,如上所述,上面的代码将允许重定向到 example.com 上的 URL,这虽然无害,但可能并非预期。您可以用自己的域(如果已知)替换 example.com 以防止这种情况。

参考资料

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