客户端请求伪造¶
ID: js/client-side-request-forgery
Kind: path-problem
Security severity: 5.0
Severity: error
Precision: medium
Tags:
- security
- external/cwe/cwe-918
Query suites:
- javascript-security-extended.qls
- javascript-security-and-quality.qls
在传出 HTTP 请求的 URL 中直接包含用户输入,可能会导致请求伪造攻击,攻击者会修改请求以针对非预期的 API 端点或资源。客户端伪造的请求可能会执行影响受害者帐户的不希望的操作,或者如果请求响应以不安全的方式处理,可能会导致跨站点脚本。这与 CSRF(跨站点请求伪造)不同,并且通常会绕过 CSRF 防护。这通常不像 SSRF(服务器端请求伪造)那样严重,因为它不会暴露内部服务。
建议¶
限制传出请求 URL 中的用户输入,尤其是
避免在 URL 的主机名中使用用户输入。从允许列表中选择主机名,而不是直接从用户输入构建它。
在用户输入是 URL 路径名的一部分时要小心。限制输入,以防止路径遍历(“
../
”)被用来将请求重定向到非预期的端点。
示例¶
以下示例显示了一个用于获取消息预渲染的 HTML 主体的 HTTP 请求。它使用端点 /api/messages/ID
,该端点被认为会响应安全 HTML 字符串,以便嵌入到页面中
async function loadMessage() {
const query = new URLSearchParams(location.search);
const url = '/api/messages/' + query.get('message_id');
const data = await (await fetch(url)).json();
document.getElementById('message').innerHTML = data.html;
}
但是,消息 ID 的格式没有经过检查,攻击者可以利用这一点来更改请求所针对的端点。如果他们可以将其重定向到返回不受信任值的端点,则会导致跨站点脚本。
例如,给定查询字符串 message_id=../pastebin/123
,请求最终会针对 /api/pastebin
端点。或者,如果登录页面上存在开放式重定向,则类似 message_id=../../login?redirect_url=https://evil.com
的查询字符串可能会使攻击者完全控制响应。
在下面的示例中,输入被限制为数字,因此无法更改端点
async function loadMessage() {
const query = new URLSearchParams(location.search);
const url = '/api/messages/' + Number(query.get('message_id'));
const data = await (await fetch(url)).json();
document.getElementById('message').innerHTML = data.html;
}