Dns Rebinding in Axum with Jwt Tokens
Dns Rebinding in Axum with Jwt Tokens — how this specific combination creates or exposes the vulnerability
DNS rebinding is a client-side attack where an attacker tricks a victim’s browser into resolving a domain to an internal IP address that the victim can reach, often bypassing same-origin policy and network boundaries. In an Axum application that relies on JWT tokens for authentication, this combination can expose authorization and session fixation risks when token handling is tied to hostname or origin checks without additional verification.
Consider an Axum API that validates requests using JWT tokens but uses the request’s host header or origin to make authorization decisions or to route between services. During a DNS rebinding scenario, an attacker registers a domain (for example, example.com) that initially resolves to a public attacker server and later, via DNS updates, to an internal service IP such as 127.0.0.1 or a corporate network resource. When a victim’s browser makes requests, it sends the attacker-controlled hostname in the Host header while the connection lands on the internal endpoint. If the Axum service trusts the Host header for routing or for constructing redirect URLs, it may inadvertently accept tokens issued for the public domain and apply them to the internal endpoint.
JWT tokens themselves are typically cryptographically signed and may include claims like iss (issuer), aud (audience), and host/URI constraints. If validation only checks token signature and expiry but does not strictly enforce audience or issuer constraints relative to the expected service endpoint, an attacker can present a valid token that was issued for one logical service but reuse it through a rebinded host. This can lead to privilege escalation if the token has broader scopes or roles than intended for the rebinded target, or it can enable unauthorized access to internal APIs that mistakenly trust the Host header.
Moreover, if the Axum service exposes endpoints that return sensitive data based on token claims without correlating the request’s network destination, an attacker may leverage DNS rebinding to probe internal services. The browser’s same-origin policy can be bypassed because the attacker controls the DNS record and can make the victim’s browser send authenticated requests to the internal IP, with the JWT attached automatically via cookies or Authorization headers. The Axum application must therefore treat the hostname as untrusted and enforce strict token audience validation and network-level isolation rather than relying on host-based checks.
In practice, this risk is not about breaking the JWT signature but about contextual misuse: trusting the Host header for authorization, failing to validate audience/issuer strictly, and allowing tokens issued for one logical service to be accepted by another endpoint reachable through rebinding. MiddleBrick’s scans detect such misconfigurations by correlating OpenAPI/Swagger specifications with runtime behavior across 12 security checks, including Authentication and Property Authorization, to highlight where token validation does not adequately constrain the request origin or audience.
Jwt Tokens-Specific Remediation in Axum — concrete code fixes
Remediation centers on strict JWT validation and removing reliance on mutable request metadata such as Host or Origin. In Axum, use a dedicated JWT validation layer that enforces audience, issuer, and, where applicable, host or URI constraints before authorizing any request. Below are concrete, working examples for Axum using the jsonwebtoken crate.
First, define your claims structure and validation parameters. Ensure the audience and issuer are checked against expected values, and avoid using the hostname for authorization logic.
use axum::{routing::get, Router};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation, TokenData};
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String,
aud: String,
iss: String,
exp: usize,
// do not rely on hostname claims for security decisions
}
async fn validate_token(token: &str) -> Result, jsonwebtoken::errors::Error> {
let decoding_key = DecodingKey::from_secret("your-secret".as_ref());
let mut validation = Validation::new(Algorithm::HS256);
validation.set_audience(&["my-api.example.com"]);
validation.set_issuer(&["auth.example.com"]);
validation.in_custom = None; // no custom host validation here
decode::(token, &decoding_key, &validation)
}
async fn handler(
headers: axum::http::HeaderMap,
// other extractors
) -> Result {
let auth_header = headers.get("authorization")
.ok_or((axum::http::StatusCode::UNAUTHORIZED, "missing authorization".to_string()))?
.to_str()
.map_err(|_| (axum::http::StatusCode::UNAUTHORIZED, "invalid auth header".to_string()))?;
let token = auth_header.strip_prefix("Bearer ").ok_or((axum::http::StatusCode::UNAUTHORIZED, "invalid bearer".to_string()))?;
let data = validate_token(token).map_err(|e| (axum::http::StatusCode::UNAUTHORIZED, format!("invalid token: {}", e)))?;
// proceed with business logic using data.claims.sub, not request host
Ok(format!("user: {}", data.claims.sub))
}
fn app() -> Router {
Router::new().route("/profile", get(handler))
}
This example avoids using the Host header for token validation and enforces audience and issuer. For scenarios where you must bind tokens to a specific service endpoint, include a custom claim (e.g., service_uri) validated against a strict allowlist rather than the request’s hostname.
Additionally, ensure your Axum service does not expose internal endpoints via rebindable hosts. Use network segmentation and explicit route definitions so that tokens issued for one audience cannot be reused against unintended internal endpoints. MiddleBrick’s Pro plan supports continuous monitoring and CI/CD integration to detect when token validation rules are too permissive or when OpenAPI specs diverge from runtime behavior, helping you maintain a robust posture against DNS rebinding and related authorization issues.