不完整的 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
清理不受信任的 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);
}
});
参考¶
OWASP:SSRF
OWASP:XSS 未经验证的重定向和转发备忘单。
通用弱点枚举:CWE-20。