CodeQL 文档

不完整的 URL 子字符串清理

ID: js/incomplete-url-substring-sanitization
Kind: problem
Security severity: 7.8
Severity: warning
Precision: high
Tags:
   - correctness
   - security
   - external/cwe/cwe-020
Query suites:
   - javascript-code-scanning.qls
   - javascript-security-extended.qls
   - javascript-security-and-quality.qls

点击查看 CodeQL 仓库中的查询

清理不受信任的 URL 是防止请求伪造和恶意重定向等攻击的重要技术。通常,这是通过检查 URL 的主机是否在允许的主机集中完成的。

但是,将 URL 视为字符串并检查允许的主机之一是否为 URL 的子字符串非常容易出错。恶意 URL 可以通过将允许的主机之一嵌入到意外位置来绕过此类安全检查。

即使子字符串检查没有在安全关键上下文中使用,不完整的检查在检查意外成功时仍可能导致不良行为。

建议

在对主机值进行检查之前解析 URL,并确保检查正确处理任意子域序列。

示例

以下示例代码检查 URL 重定向是否将到达example.com域或其子域之一,而不是某些恶意站点。

app.get('/some/path', function(req, res) {
    let url = req.param("url");
    // BAD: the host of `url` may be controlled by an attacker
    if (url.includes("example.com")) {
        res.redirect(url);
    }
});

但是,子字符串检查很容易绕过。例如,通过将example.com嵌入到路径组件中:http://evil-example.net/example.com,或嵌入到查询字符串组件中:http://evil-example.net/?x=example.com。通过检查解析后的 URL 的主机来解决这些缺点。

app.get('/some/path', function(req, res) {
    let url = req.param("url"),
        host = urlLib.parse(url).host;
    // BAD: the host of `url` may be controlled by an attacker
    if (host.includes("example.com")) {
        res.redirect(url);
    }
});

这仍然不是一个充分的检查,因为以下 URL 会绕过它:http://evil-example.com http://example.com.evil-example.net。相反,使用允许主机列表的显式白名单来确保重定向安全。

app.get('/some/path', function(req, res) {
    let url = req.param('url'),
        host = urlLib.parse(url).host;
    // GOOD: the host of `url` can not be controlled by an attacker
    let allowedHosts = [
        'example.com',
        'beta.example.com',
        'www.example.com'
    ];
    if (allowedHosts.includes(host)) {
        res.redirect(url);
    }
});

参考

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