mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Rust: Add request forgery query qhelp
This commit is contained in:
54
rust/ql/src/queries/security/CWE-918/RequestForgery.qhelp
Normal file
54
rust/ql/src/queries/security/CWE-918/RequestForgery.qhelp
Normal file
@@ -0,0 +1,54 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Directly incorporating user input into an HTTP request without validating the
|
||||
input can facilitate server-side request forgery (SSRF) attacks. In these
|
||||
attacks, the server may be tricked into making a request to an unintended API
|
||||
endpoint or resource.
|
||||
|
||||
If the server performing the request is connected to an internal network, this
|
||||
can give an attacker the means to bypass the network boundary and make requests
|
||||
against internal services.
|
||||
|
||||
A forged request may perform an unintended action on behalf of the attacker, or
|
||||
cause information leak if redirected to an external server or if the request
|
||||
response is fed back to the user. It may also compromise the server making the
|
||||
request, if the request response is handled in an unsafe way.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
To guard against SSRF attacks you should avoid putting user-provided input
|
||||
directly into a request URL. Instead, maintain a list of authorized URLs on the
|
||||
server; then choose from that list based on the input provided. Alternatively,
|
||||
ensure requests constructed from user input are limited to a particular host or
|
||||
more restrictive URL prefix.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows an HTTP request parameter being used directly to
|
||||
form a new request without validating the input, which facilitates SSRF attacks.
|
||||
It also shows how to remedy the problem by validating the user input against a
|
||||
known fixed string.
|
||||
</p>
|
||||
|
||||
<sample src="RequestForgery.rs" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">OWASP SSRF</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://cwe.mitre.org/data/definitions/918.html">CWE-918: Server-Side Request Forgery (SSRF)</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
39
rust/ql/src/queries/security/CWE-918/RequestForgery.rs
Normal file
39
rust/ql/src/queries/security/CWE-918/RequestForgery.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
// BAD: Endpoint handler that makes requests based on user input
|
||||
async fn vulnerable_endpoint_handler(req: Request) -> Result<Response> {
|
||||
// This request is vulnerable to SSRF attacks as the user controls the
|
||||
// entire URL
|
||||
let response = reqwest::get(&req.user_url).await;
|
||||
|
||||
match response {
|
||||
Ok(resp) => {
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
Ok(Response {
|
||||
message: "Success".to_string(),
|
||||
data: body,
|
||||
})
|
||||
}
|
||||
Err(_) => Err("Request failed")
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD: Validate user input against an allowlist
|
||||
async fn secure_endpoint_handler(req: Request) -> Result<Response> {
|
||||
// Allow list of specific, known-safe URLs
|
||||
let allowed_hosts = ["api.example.com", "trusted-service.com"];
|
||||
|
||||
if !allowed_hosts.contains(&req.user_url) {
|
||||
return Err("Untrusted domain");
|
||||
}
|
||||
// This request is safe as the user input has been validated
|
||||
let response = reqwest::get(&req.user_url).await;
|
||||
match response {
|
||||
Ok(resp) => {
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
Ok(Response {
|
||||
message: "Success".to_string(),
|
||||
data: body,
|
||||
})
|
||||
}
|
||||
Err(_) => Err("Request failed")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user