Arp Spoofing in Actix
How ARP Spoofing Manifests in Actix Web Applications
ARP spoofing is a layer-2 network attack where an attacker sends falsified ARP messages onto a local network, linking their MAC address with the IP address of a legitimate host (like a gateway or another client). This enables man-in-the-middle (MITM) or denial-of-service attacks at the network level. While ARP spoofing is fundamentally a network infrastructure issue, its effects can manifest in an Actix Web application through the application's trust in network-layer or transport-layer identity signals.
Actix Web, as a high-performance Rust HTTP framework, often runs behind reverse proxies (Nginx, HAProxy, Cloudflare) in production. A common pattern is to extract the client's original IP address from the X-Forwarded-For (XFF) header for logging, rate limiting, or access control. If the Actix application is configured to trust any proxy or fails to validate the XFF header chain, an attacker who has successfully performed ARP spoofing against the reverse proxy's network segment can inject a spoofed XFF header. This allows them to impersonate a trusted internal IP address (e.g., 10.0.0.5 from the corporate network) from a malicious external source.
Consider this Actix handler that uses the remote_addr() method, which by default may return the proxy's IP, not the client's:
use actix_web::{web, HttpResponse, Responder};
async fn get_sensitive_data(req: web::HttpRequest) -> impl Responder {
let client_ip = req.connection_info().realip_remote_addr();
// Logic that grants access based on IP allowlist
if is_internal_ip(client_ip.unwrap_or("0.0.0.0".to_string())) {
HttpResponse::Ok().json("Sensitive internal data")
} else {
HttpResponse::Forbidden().into_body()
}
}If the Actix app is deployed with an TrustedProxy set to 0.0.0.0/0 (trust all) or not configured at all, realip_remote_addr() will use the XFF header if present. An attacker who has ARP-spoofed the proxy can send a request with X-Forwarded-For: 10.0.0.5. The application, trusting the header, will see client_ip as 10.0.0.5 and bypass IP-based controls. This is a classic Security Misconfiguration (OWASP API Security Top 10: API10:2023 - Security Misconfiguration) where the application incorrectly assumes network-layer identity.
The vulnerability is exacerbated if the application uses the extracted IP for session fixation protection, CSRF token validation tied to IP, or as part of a key in cache partitioning. The root cause is not in Actix itself but in how the developer configures proxy trust and processes the XFF header. ARP spoofing provides the network position to inject the malicious header, while the Actix app's insecure configuration completes the exploit chain.
Actix-Specific Detection: Finding Misconfigured Proxy Trust
Detecting this issue in an Actix application involves two phases: runtime behavior analysis and configuration review. The core indicator is whether the application's perceived client IP can be controlled by an attacker via the X-Forwarded-For header when it should only be set by the trusted reverse proxy.
Manual Testing: Send a request directly to the Actix service (bypassing the intended proxy, e.g., via curl to the service port) with a spoofed XFF header:
curl -H "X-Forwarded-For: 192.168.1.100" http://actix-app-internal:8080/adminIf the application logs or behaves as if the request came from 192.168.1.100 (e.g., grants access to an IP-restricted endpoint), the TrustedProxy is misconfigured or absent. Actix's ConnectionInfo provides realip_remote_addr() and peer_addr(). The former uses XFF if trusted proxies are set; the latter is the direct TCP peer (the proxy's IP if present). A discrepancy where realip_remote_addr() differs from peer_addr() when no legitimate proxy is in the path confirms header trust.
Automated Scanning with middleBrick: middleBrick's black-box scanner tests the unauthenticated attack surface of the API endpoint. Its Authentication and Input Validation checks include tests for proxy header manipulation. When scanning an Actix application, middleBrick will:
- Submit requests with manipulated
X-Forwarded-For,X-Real-IP, andForwardedheaders. - Observe changes in response status codes, response bodies, or rate limiting thresholds that indicate IP-based logic is being influenced by the supplied header.
- Cross-reference findings with the OpenAPI/Swagger spec (if provided) to see if IP-related parameters are defined in security schemes or path operations.
A finding would be categorized under Authentication or Security Misconfiguration with a severity based on the impact (e.g., privilege escalation if IP allowlists are bypassed). The report provides the exact request/response pairs showing the header manipulation and the resulting behavioral change. For an Actix app, middleBrick's CLI tool can be used in scripts to validate fixes:
middlebrick scan https://api.example.com --output json | jq '.findings[] | select(.category=="Authentication")'Integrating the GitHub Action into the CI/CD pipeline for the Actix service ensures that any deployment with a misconfigured TrustedProxy (e.g., accidentally set to 0.0.0.0/0 in main.rs) triggers a build failure if the security score drops below a defined threshold.
Actix-Specific Remediation: Secure Proxy Configuration
Remediation in Actix Web centers on correctly configuring trusted proxies and never trusting client-supplied headers by default. The framework provides explicit tools for this.
1. Configure a Strict TrustedProxy: In main.rs or your server setup, define the TrustedProxy to match only the IP addresses or CIDR ranges of your actual reverse proxies. Never use 0.0.0.0/0 (trust all) in production.
use actix_web::{dev::Server, http::header, App, HttpServer, HttpResponse};
use actix_web::http::header::HeaderValue;
use actix_web::rt::System;
fn main() -> std::io::Result<()> {
let server = HttpServer::new(|| {
App::new()
// Configure trusted proxies to ONLY your load balancer/reverse proxy IPs
.app_data(actix_web::web::Data::new(
actix_web::HttpRequest::trusted_proxy(
// Example: single IP
// std::net::IpAddr::from([10, 0, 0, 10])
// Or a CIDR range for a pool of proxies
std::net::IpAddr::from([10, 0, 0, 0]), 16 // /16 network
)
))
.route("/", web::get().to(index))
.route("/admin", web::get().to(admin))
})
.bind("127.0.0.1:8080")?
.run();
System::new().block_on(server)?;
Ok(())
}With this, req.connection_info().realip_remote_addr() will only use the X-Forwarded-For header if the immediate TCP peer (peer_addr()) matches the trusted proxy list. An attacker not on the trusted network cannot spoof the XFF header to influence the result.
2. Validate the XFF Chain: If your proxy appends to the XFF header (standard practice), you might need to validate the entire chain. Actix does not provide built-in chain validation, so implement a custom middleware that checks the left-most (client-originated) IP against a blocklist or ensures the right-most (proxy-added) IPs are from trusted networks.
use actix_web::{dev::Service, http::header::Header, HttpRequest, HttpResponse, Result};
use std::net::IpAddr;
struct XffValidation;
impl Service for XffValidation {
type Response = B;
type Error = actix_web::Error;
type Future = std::pin::Pin>>>;
fn poll_ready(&self, _: &mut Context<'_>) -> Poll> {
Poll::Ready(Ok(()))
}
fn call(&self, req: &HttpRequest, srv: &S) -> Self::Future {
let trusted_proxies: Vec = vec![
std::net::IpAddr::from([10, 0, 0, 10]),
std::net::IpAddr::from([10, 0, 0, 11]),
];
let fut = async move {
// Only validate if request came through a trusted proxy
let peer_addr = req.connection_info().peer_addr().unwrap_or("0.0.0.0").parse().unwrap_or(IpAddr::from([0,0,0,0]));
if trusted_proxies.contains(&peer_addr) {
if let Some(xff) = req.headers().get("x-forwarded-for") {
if let Ok(xff_str) = xff.to_str() {
let ips: Vec<&str> = xff_str.split(',').map(|s| s.trim()).collect();
// The right-most IP should be the last proxy that added to the chain
// Ensure all IPs in the chain (except possibly the client IP) are trusted
// Simplified: check that the second-to-last IP is trusted
if ips.len() >= 2 {
let second_last = ips[ips.len()-2].parse::().unwrap_or(IpAddr::from([0,0,0,0]));
if !trusted_proxies.contains(&second_last) {
return Err(actix_web::error::ErrorForbidden("Invalid X-Forwarded-For chain"));
}
}
}
}
}
Ok(srv.call(req).await?)
};
Box::pin(fut)
}
}
// Then wrap your app: .wrap(XffValidation) 3. Use Rate Limiting Based on peer_addr(): For rate limiting, use the direct TCP peer address (req.connection_info().peer_addr()) rather than realip_remote_addr(), as the peer address cannot be spoofed via HTTP headers. Actix's actix-web-limiter crate or custom middleware can enforce this. This prevents an ARP-spoofing attacker from bypassing rate limits by rotating spoofed XFF IPs.
4. Defense in Depth: While not Actix-specific, ensure your network infrastructure (switches, routers) has ARP spoofing protection (e.g., DHCP snooping, dynamic ARP inspection). The application-level fix is critical because network controls can be bypassed in compromised segments. middleBrick's continuous monitoring (available in the Pro plan) can regularly scan your Actix API to ensure the TrustedProxy configuration remains strict and that no new proxy-related misconfigurations have been introduced.