服务器端请求伪造¶
ID: js/request-forgery
Kind: path-problem
Security severity: 9.1
Severity: error
Precision: high
Tags:
- security
- external/cwe/cwe-918
Query suites:
- javascript-code-scanning.qls
- javascript-security-extended.qls
- javascript-security-and-quality.qls
在传出 HTTP 请求的 URL 中直接包含用户输入可能会导致请求伪造攻击,攻击者会修改请求以攻击意外的 API 端点或资源。如果执行请求的服务器连接到内部网络,这可能会使攻击者能够绕过网络边界并对内部服务发出请求。伪造的请求可能会代表攻击者执行意外的操作,或者如果重定向到外部服务器或请求响应被反馈给用户,则会导致信息泄露。如果请求响应的处理方式不安全,它也可能危及发出请求的服务器。
建议¶
限制传出请求的 URL 中的用户输入,特别是
避免在 URL 的主机名中使用用户输入。从允许列表中选择主机名,而不是直接从用户输入中构建主机名。
当用户输入是 URL 的路径名的一部分时要小心。限制输入,以便无法使用路径遍历(“
../
”)将请求重定向到意外的端点。
示例¶
以下示例显示了 HTTP 请求参数在未验证输入的情况下直接用于请求的 URL 中,这会造成 SSRF 攻击。请求 http.get(...)
是脆弱的,因为攻击者可以选择任何他们想要的 target
值。例如,攻击者可以选择 "internal.example.com/#"
作为目标,导致请求中使用的 URL 为 "https://internal.example.com/#.example.com/data"
。
如果该服务器不应该直接从攻击者的机器访问,那么对 https://internal.example.com
的请求可能会有问题。
import http from 'http';
const server = http.createServer(function(req, res) {
const target = new URL(req.url, "http://example.com").searchParams.get("target");
// BAD: `target` is controlled by the attacker
http.get('https://' + target + ".example.com/data/", res => {
// process request response ...
});
});
解决问题的一种方法是在执行请求之前使用用户输入来选择已知的固定字符串
import http from 'http';
const server = http.createServer(function(req, res) {
const target = new URL(req.url, "http://example.com").searchParams.get("target");
let subdomain;
if (target === 'EU') {
subdomain = "europe"
} else {
subdomain = "world"
}
// GOOD: `subdomain` is controlled by the server
http.get('https://' + subdomain + ".example.com/data/", res => {
// process request response ...
});
});