Ssrf Server Side in Actix
How SSRF Manifests in Actix Applications
Server-Side Request Forgery (SSRF) in Actix applications occurs when user-controlled input is used to construct URLs for outbound HTTP requests without proper validation. In Actix, this typically happens in handler functions where parameters from HTTP requests are directly passed to HTTP clients or URL parsing functions.
A common pattern in Actix applications involves using the http crate or reqwest to make outbound requests. When user input like user_id or redirect_url is incorporated into these requests without validation, attackers can manipulate the input to target internal services. For example:
async fn proxy_handler(&self, req: HttpRequest) -> impl Responder {
let target_url = req.query("url").unwrap_or("http://default").to_string();
let client = reqwest::Client::new();
let res = client.get(&target_url).send().await.unwrap();
HttpResponse::build(res.status()).body(res.text().await.unwrap())
}
This Actix handler directly uses the url query parameter to make an outbound request. An attacker could supply http://localhost:8080/internal or http://169.254.169.254/latest/meta-data/ to access internal metadata services or internal APIs.
Actix applications often integrate with cloud services, databases, or internal microservices. SSRF vulnerabilities become particularly dangerous when Actix handlers proxy requests to these services. The framework's async nature means these requests execute immediately, potentially exposing internal network services that aren't meant to be publicly accessible.
Another Actix-specific manifestation involves using the actix-web-httpclient or similar crates for outbound requests. When user input flows through Actix's request extraction and validation pipeline without proper sanitization, SSRF vulnerabilities emerge. The framework's strong typing can actually make these vulnerabilities more subtle, as developers might assume type safety provides security guarantees.
Actix-Specific Detection Methods
Detecting SSRF in Actix applications requires both static analysis and runtime scanning. Static analysis should focus on identifying patterns where user input flows to URL construction or HTTP client calls. Look for:
- Query parameters, path parameters, or JSON body fields used in URL construction
- Direct use of
reqwest::get(),http::Request::get(), or similar outbound request functions - URL parsing without validation (
Url::parse()with user input) - Configuration files with templated URLs containing user data
Runtime scanning with middleBrick provides comprehensive SSRF detection for Actix applications. The scanner tests unauthenticated endpoints by sending payloads designed to trigger SSRF behavior. middleBrick's black-box scanning approach is particularly effective because it doesn't require access to source code or internal APIs.
middleBrick's SSRF detection includes testing for:
- Localhost and loopback address access attempts
- Private IP range requests (10.x, 172.16-31.x, 192.168.x)
- Link-local and multicast address access
- Cloud provider metadata service endpoints (169.254.169.254, 169.254.170.2)
- Internal domain names and DNS rebinding attempts
The scanner provides a security score (0-100) with specific findings for each vulnerability category. For SSRF, middleBrick reports the exact payloads that triggered internal service access, making remediation straightforward. The tool also checks for missing rate limiting and input validation, which often accompany SSRF vulnerabilities.
middleBrick's continuous monitoring capability is valuable for Actix applications in production. APIs can be scanned on a configurable schedule, with alerts sent when SSRF vulnerabilities are detected or when security scores drop below thresholds. This proactive approach helps catch SSRF issues before attackers exploit them.
Actix-Specific Remediation Techniques
Remediating SSRF in Actix applications requires a defense-in-depth approach. The most effective strategy combines input validation, allowlisting, and architectural controls. Here's how to implement these in Actix:
Input validation should occur at the handler level before any URL construction. Use Actix's strong typing to extract and validate parameters:
use actix_web::{get, HttpResponse, Responder};
use url::Url;
use std::net::IpAddr;
#[get("/proxy")]
async fn proxy_handler(
query: actix_web::web::Query<QueryParams>,
) -> impl Responder {
// Validate URL format
let target_url = match Url::parse(&query.url) {
Ok(url) if is_allowed_url(&url) => url,
_ => return HttpResponse::BadRequest().body("Invalid URL"),
};
// Check for private IP addresses
if is_private_ip(&target_url.host_str().unwrap_or("")) {
return HttpResponse::BadRequest().body("Private addresses not allowed");
}
// Proceed with request
let client = reqwest::Client::new();
let res = client.get(target_url).send().await.unwrap();
HttpResponse::build(res.status()).body(res.text().await.unwrap())
}
fn is_allowed_url(url: &Url) -> bool {
// Allowlist specific domains
matches!(url.host_str(), Some("api.example.com") | Some("cdn.example.net"))
}
fn is_private_ip(host: &str) -> bool {
if let Ok(ip) = host.parse::() {
ip.is_private() || ip.is_loopback()
} else {
false
}
}
This Actix handler validates URLs against an allowlist and checks for private IP addresses before making outbound requests. The is_allowed_url function restricts requests to specific trusted domains, while is_private_ip blocks internal network access.
For more complex scenarios, implement a dedicated URL validation service:
use actix_web::middleware::Next;
use url::Url;
use std::collections::HashSet;
pub struct UrlValidationMiddleware {
allowed_hosts: HashSet<String>,
}
impl actix_web::middleware::Transform for UrlValidationMiddleware
where
S: actix_web::dev::Service<Request = actix_web::dev::ServiceRequest, Response = actix_web::dev::ServiceResponse>,
{
type Request = actix_web::dev::ServiceRequest;
type Response = actix_web::dev::ServiceResponse;
type Error = actix_web::Error;
type Transform = UrlValidationMiddlewareService;
fn new_transform(&self, service: S) -> Self::Transform {
UrlValidationMiddlewareService {
service,
allowed_hosts: self.allowed_hosts.clone(),
}
}
}
pub struct UrlValidationMiddlewareService<S> {
service: S,
allowed_hosts: HashSet<String>,
}
impl<S> actix_web::dev::Service for UrlValidationMiddlewareService<S>
where
S: actix_web::dev::Service<Request = actix_web::dev::ServiceRequest, Response = actix_web::dev::ServiceResponse>,
{
type Request = actix_web::dev::ServiceRequest;
type Response = actix_web::dev::ServiceResponse;
type Error = actix_web::Error;
type Future = actix_web::dev::ServiceResponseFuture;
actix_web::dev::forward_ready!(service);
fn call(&mut self, req: Self::Request) -> Self::Future {
// Check if this request needs URL validation
if let Some(url) = extract_target_url(&req) {
if !self.is_url_allowed(&url) {
return Box::pin(async move {
Ok(req.error_response(
actix_web::error::InternalError::new(
"URL not allowed",
actix_web::http::StatusCode::BAD_REQUEST,
),
))
});
}
}
self.service.call(req)
}
}
fn extract_target_url(req: &actix_web::dev::ServiceRequest) -> Option<Url> {
// Extract URL from query parameters or body
None
}
fn is_url_allowed(url: &Url) -> bool {
// Implement allowlist logic
true
}
This middleware approach centralizes URL validation across all Actix handlers, ensuring consistent SSRF protection throughout the application.
Additional architectural controls include:
- Network segmentation to isolate internal services
- DNS filtering to block resolution of internal domains
- Outbound proxy configuration with strict allowlisting
- Rate limiting on outbound requests to prevent abuse
- Monitoring and alerting for unusual outbound request patterns
middleBrick's remediation guidance specifically addresses Actix patterns, providing code examples and configuration recommendations tailored to Rust and Actix's async architecture. The tool's findings include severity levels and step-by-step remediation instructions that integrate seamlessly with Actix's error handling and middleware patterns.
Frequently Asked Questions
How does SSRF differ in Actix applications compared to other frameworks?
reqwest crate for outbound requests and Actix's async handler functions. The framework's strong typing can make SSRF vulnerabilities more subtle, as developers might assume type safety provides security guarantees. Actix's middleware system also allows for centralized SSRF protection through request validation layers.