Dns Rebinding in Axum with Api Keys
Dns Rebinding in Axum with Api Keys — how this specific combination creates or exposes the vulnerability
DNS rebinding is a client-side attack where a malicious webpage causes a victim’s browser to resolve a hostname to an internal IP address that differs over time, often bypassing same-origin policy and access controls. In Axum applications that rely on API keys for authorization, this can expose protected endpoints to a browser-originated request that should not be permitted.
Consider an Axum service that uses static API keys passed via HTTP headers (e.g., x-api-key) to authorize requests. If the service performs authorization only once per request and does not validate the origin or enforce additional protections, a crafted webpage can make repeated requests to the Axum endpoint. Through DNS rebinding, the attacker alternates the DNS response between a public IP they control and an internal service IP (e.g., 127.0.0.1 or a private service endpoint). The victim’s browser is tricked into sending requests with valid API keys, potentially allowing the attacker to invoke internal or administrative routes that should not be reachable from the public internet.
The risk is compounded when the Axum application exposes routes that return sensitive data or perform state-changing operations, and when those routes do not validate the request origin beyond the presence of an API key. Because the API key is static and included in requests initiated by the browser, the rebinding chain can succeed without the service detecting an abnormal source IP or a cross-origin context. This effectively bypasses network-based isolation and exposes functionality that was intended for server-to-server or authenticated client use only.
In practice, an attacker might use a simple HTML/JavaScript page to rotate A records so that the victim’s browser alternates between an attacker-controlled domain and the target service. The Axum service sees requests with valid API keys but may not correlate the request’s origin, the referer header, or the expected scope of API key usage. Without additional checks—such as CORS policies that restrict origins, anti-rebinding defenses like SRI or strict referer validation, or runtime checks that ensure the client IP aligns with an expected trust boundary—an otherwise properly configured API key mechanism can be undermined by DNS rebinding.
middleBrick’s scans include checks related to Input Validation and Property Authorization, which can surface exposed routes that may be vulnerable when combined with weak origin or referer validation. These findings highlight where additional controls are necessary to mitigate DNS rebinding in an Axum service that uses API keys.
Api Keys-Specific Remediation in Axum — concrete code fixes
To reduce DNS rebinding risk in Axum when using API keys, apply controls at the authorization and routing layers. Do not rely solely on the presence of an API key; enforce origin constraints and validate request context. Below are concrete code examples that demonstrate these protections.
1. Validate the Referer and Origin headers
Check the Referer and Origin headers to ensure requests originate from an expected domain. This helps prevent browser-initiated requests from malicious sites.
use axum::{routing::get, Router, extract::Request, http::HeaderMap};
use std::net::SocketAddr;
use tower_http::services::ServeDir;
async fn validate_origin(req: Request) -> Result<(), (axum::http::StatusCode, &'static str)> {
let origin = req.headers().get("origin").and_then(|v| v.to_str().ok());
let referer = req.headers().get("referer").and_then(|v| v.to_str().ok());
let allowed = match (origin, referer) {
// Accept requests from our known frontend
(Some("https://app.example.com"), _) => true,
(_, Some("https://app.example.com")) => true,
// Or match a subdomain pattern programmatically
(Some(o), _) if o.ends_with(".example.com") => true,
_ => false,
};
if allowed {
Ok(())
} else {
Err((axum::http::StatusCode::FORBIDDEN, "Invalid origin"))
}
}
async fn handler() -> &'static str {
"ok"
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/api/data", get(|req: Request| async move {
validate_origin(req).await?;
handler().await
}));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr).serve(app.into_make_service()).await.unwrap();
}
2. Use Axum middleware to enforce API key scope and binding
Create a middleware that checks the API key and also records or validates the source IP range to detect unlikely transitions (a signal of rebinding). This complements header checks and ensures API keys are not used in unexpected network contexts.
use axum::{async_trait, extract::FromRequestParts, http::request::Parts};
use std::collections::HashSet;
struct ValidatedApiKey(String);
#[async_trait]
impl FromRequestParts for ValidatedApiKey {
type Rejection = (axum::http::StatusCode, &'static str);
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result {
let headers = &parts.headers;
let key = headers.get("x-api-key")
.and_then(|v| v.to_str().ok())
.ok_or((axum::http::StatusCode::UNAUTHORIZED, "Missing API key"))?;
// Example static key validation (in practice, use a secure store)
const ALLOWED_KEYS: &[&str] = &["trusted-key-123", "admin-key-456"];
if !ALLOWED_KEYS.contains(&key) {
return Err((axum::http::StatusCode::UNAUTHORIZED, "Invalid API key"));
}
// Optionally bind key to a source IP range or other context
if let Some(remote_addr) = parts.extensions.get::() {
// Implement additional checks, e.g., ensure IP is within expected subnet
// For rebinding mitigation, log or reject improbable IP transitions
}
Ok(ValidatedApiKey(key.to_string()))
}
}
// Usage in a route:
async fn secure_endpoint(ValidatedApiKey(key): ValidatedApiKey) -> &'static str {
"secure data"
}
3. Combine with CORS and anti-rebinding defenses
Use Axum’s CORS layer to restrict origins tightly. Also consider including a nonce or a request-scoped token to ensure freshness, and avoid exposing sensitive operations via GET endpoints that can be prefetched by browsers.
use axum::Router;
use tower_http::cors::{CorsLayer, Any};
let cors = CorsLayer::new()
.allow_origin(Any::new(|origin| {
origin == "https://app.example.com"
}))
.allow_methods(Any::len(1).map(|_| axum::http::Method::GET));
let app = Router::new()
.route("/api/data", get(handler))
.layer(cors);
middleBrick scans can help identify routes that lack origin validation or show unusual patterns in authorization that may be exploitable via DNS rebinding. Applying these Axum-specific mitigations reduces the likelihood of API keys being abused in a browser-based rebinding scenario.