Ssrf Server Side in Axum
How SSRF Manifests in Axum Applications
Server-Side Request Forgery (SSRF) in Axum applications occurs when user-controlled input is used to construct HTTP requests from the server to external resources. In Rust web applications built with Axum, this vulnerability typically manifests through endpoint parameters, query strings, or request bodies that are directly passed to HTTP clients without proper validation.
Axum's async/await architecture and the widespread use of reqwest or similar HTTP clients in the ecosystem create specific SSRF patterns. Consider this vulnerable Axum route:
use axum::{routing::get, Router, Json, http::StatusCode};
use reqwest::get;
async fn proxy_content(url: String) -> Result<Json<serde_json::Value>, StatusCode> {
let response = get(&url).await;
match response {
Ok(resp) => {
let text = resp.text().await.unwrap_or_default();
Ok(Json(serde_json::json!({ "content": text })))
}
Err(_) => Err(StatusCode::BAD_REQUEST),
}
}
let app = Router::new()
.route("/proxy/:url", get(proxy_content));
This pattern is dangerous because Axum's extraction traits make it trivial to accept user input and pass it directly to HTTP clients. The vulnerability becomes more severe when attackers can target internal services, cloud metadata endpoints, or services that require authentication.
Common Axum SSRF vectors include:
- URL parameters in proxy endpoints that forward requests to arbitrary destinations
- Configuration endpoints that fetch schemas or definitions from user-provided URLs
- Webhook processing that makes outbound requests to attacker-controlled URLs
- API aggregation endpoints that collect data from multiple services
The Rust ecosystem's strong typing can provide some protection, but only if developers actively validate and sanitize inputs. Axum's middleware system can help implement SSRF protections, but the core issue remains: unvalidated user input reaching HTTP clients.
Axum-Specific Detection and Scanning
Detecting SSRF vulnerabilities in Axum applications requires both static analysis and runtime scanning. Static analysis can identify dangerous patterns where user input flows to HTTP clients, while runtime scanning with middleBrick can actively test for SSRF vulnerabilities without requiring source code access.
middleBrick's black-box scanning approach is particularly effective for Axum applications because it tests the actual running service. The scanner attempts SSRF payloads against your API endpoints and analyzes responses for indicators of successful exploitation. Here's how you'd scan an Axum application:
# Install middleBrick CLI
npm install -g middlebrick
# Scan your running Axum service
middlebrick scan http://localhost:3000
# Or scan with specific focus on potential SSRF endpoints
middlebrick scan --endpoint /proxy http://localhost:3000
middleBrick tests SSRF by attempting to access various internal and external resources through your API endpoints. It checks for:
- Cloud metadata service access (169.254.169.254, 169.254.169.123)
- Localhost and RFC 1918 private IP addresses
- Common internal service ports (2375, 6379, 3306, etc.)
- Protocol smuggling attempts (file://, gopher://, ftp://)
- Time-delayed requests to detect blind SSRF
For Axum developers, middleBrick's OpenAPI analysis is particularly valuable. If you have an OpenAPI spec for your Axum service, middleBrick can cross-reference parameter definitions with runtime scanning results, providing comprehensive coverage of your API surface.
The scanner's 5-15 second response time means you can integrate SSRF testing into your development workflow. Run middleBrick before committing code changes, or add it to your CI/CD pipeline to catch SSRF vulnerabilities early.
Axum-Specific Remediation Techniques
Remediating SSRF in Axum applications requires a defense-in-depth approach. The most effective strategy combines input validation, allowlist-based URL filtering, and network-layer controls. Here's how to implement these protections in Axum:
First, create a URL validation middleware that checks all incoming requests:
use axum::{middleware::Next, Request, Response};
use url::{Url, Host};
use std::net::IpAddr;
async fn ssrf_protection(mut req: Request<B>, next: Next<'_, B>) -> Result<Response, axum::BoxError> {
// Check if request has URL parameters that could be SSRF vectors
if let Some(params) = req.extensions_mut().get_mut::<axum::extract::Path<Vec<String>>>() {
for param in params {
if let Err(_) = validate_url(param) {
return Ok(Response::builder()
.status(400)
.body(axum::body::Full::from("Invalid URL"))?);
}
}
}
next.run(req).await
}
fn validate_url(input: &str) -> Result<(), &'static str> {
let url = match Url::parse(input) {
Ok(u) if u.scheme().starts_with('http') => u,
_ => return Err("Invalid URL scheme"),
};
// Block private IP ranges
if let Ok(ip) = url.host().unwrap().to_string().parse::<IpAddr>() {
if ip.is_private() || ip.is_loopback() || ip.is_link_local() {
return Err("Private IP address not allowed");
}
}
// Block cloud metadata services
if url.host().unwrap().to_string() == "169.254.169.254" {
return Err("Cloud metadata access blocked");
}
Ok(())
}
Apply this middleware to your entire application or specific routes that handle external URLs:
let app = Router::new()
.route("/proxy/:url", get(proxy_content))
.layer(axum::middleware::from_fn(ssrf_protection));
For more robust protection, implement an allowlist of permitted domains or use a service like CloudFlare to block internal network access at the edge. Additionally, configure your HTTP client with timeouts and restrictions:
use reqwest::Client;
let client = Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()
.unwrap();
This client configuration prevents slowloris attacks and limits the impact of SSRF attempts. Combine these techniques with middleBrick's continuous scanning to ensure your protections remain effective as your API evolves.