Denial Of Service in Axum with Basic Auth
Denial Of Service in Axum with Basic Auth — how this specific combination creates or exposes the vulnerability
When an Axum service uses HTTP Basic Authentication and is exposed without additional protections, the combination can amplify Denial of Service (DoS) risks. Basic Auth is a stateless challenge-response mechanism where the client sends an Authorization: Basic base64(credentials) header on each request. If the endpoint is unauthenticated from a scanning perspective, middleBrick classifies this as an unauthenticated attack surface and tests whether authentication can be bypassed. An attacker can exploit this in several ways that consume server resources:
- Credential stuffing or brute-force attempts against the Basic Auth realm trigger repeated password validation logic for each request. In Axum, if validation is performed synchronously in request guards or handlers for every call, CPU cycles are consumed per attempt, leading to high utilization under rapid requests.
- Base64 decoding and header parsing happen on every request. Malformed or very large Authorization headers can cause unnecessary allocations and garbage collection pressure, increasing latency and memory use.
- If the Basic Auth check involves expensive operations such as database or LDAP lookups per request, an unthrottled stream of requests can exhaust connection pools, thread pools, or backend service capacity, causing legitimate traffic to be delayed or dropped.
- When combined with other unchecked inputs, an endpoint that performs Basic Auth validation may become susceptible to resource exhaustion via large or deeply nested headers, or by opening many concurrent connections that are not cleaned up promptly.
middleBrick’s unauthenticated scan flags this as a potential BOLA/IDOR and Rate Limiting finding because the endpoint lacks controls like authentication, per-request rate limits, or concurrency caps. In Axum, the risk is not Basic Auth itself, but the absence of request throttling, input size limits, and efficient validation strategies that can turn a standard authentication mechanism into a DoS vector.
Basic Auth-Specific Remediation in Axum — concrete code fixes
To reduce DoS risk when using Basic Auth in Axum, focus on minimizing per-request work, adding throttling, and validating inputs early. Below are concrete, idiomatic examples that address resource consumption while preserving functionality.
1. Lightweight validation with cached credentials
Avoid expensive lookups on every request. Validate the token once and cache results (e.g., using an in-memory rate-limited cache or a shared Arc map with TTL). This example demonstrates a simple Basic Auth guard that performs a constant-time comparison and avoids blocking calls per request:
use axum::{
async_trait, extract::Request, http::HeaderValue, response::IntoResponse,
routing::get, Router,
};
use std::{
collections::HashMap,
convert::Infallible,
sync::{Arc, Mutex},
};
// Cached credentials; in production use a TTL cache or secure store.
struct Credentials {
user: String,
pass: String, // store only hashes in real use
}
#[derive(Clone)]
struct SharedState {
valid: Arc>>,
// Add request counters or rate limiter state here
}
async fn validate_basic_auth(
headers: &axum::http::HeaderMap,
state: SharedState,
) -> Result {
let auth = headers
.get(axum::http::header::AUTHORIZATION)
.and_then(|v| v.to_str().ok())
.ok_or((axum::http::StatusCode::UNAUTHORIZED, "Missing header".to_string()))?;
if !auth.starts_with("Basic ") {
return Err((axum::http::StatusCode::UNAUTHORIZED, "Wrong scheme".to_string()));
}
let decoded = base64::decode(&auth[6..]).map_err(|_| (axum::http::StatusCode::UNAUTHORIZED, "Bad encoding"))?;
let parts: Vec<&str> = std::str::from_utf8(&decoded).map_err(|_| (axum::http::StatusCode::UNAUTHORIZED, "Invalid utf8"))?.splitn(2, ':').collect();
if parts.len() != 2 {
return Err((axum::http::StatusCode::UNAUTHORIZED, "Invalid credentials format".to_string()));
}
let (user, pass) = (parts[0], parts[1]);
// Constant-time comparison pattern to reduce timing variance
let stored = state.valid.read().unwrap().get(user).ok_or((axum::http::StatusCode::UNAUTHORIZED, "Not found"))?;
let user_match = subtle::ConstantTimeEq::ct_eq(user.as_bytes(), stored.user.as_bytes());
let pass_match = subtle::ConstantTimeEq::ct_eq(pass.as_bytes(), stored.pass.as_bytes());
if user_match && pass_match == subtle::Choice::from(1u8) {
Ok(stored.clone())
} else {
Err((axum::http::StatusCode::UNAUTHORIZED, "Invalid credentials".to_string()))
}
}
async fn handler() -> impl IntoResponse {
"OK"
}
#[tokio::main]
async fn main() {
let mut map = HashMap::new();
map.insert("alice".to_string(), Credentials { user: "alice".to_string(), pass: "s3cret".to_string() });
let state = SharedState { valid: Arc::new(Mutex::new(map)) };
let app = Router::new()
.route("/api/me", get(handler))
.with_state(state);
// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
}
2. Add rate limiting and request size controls
Prevent resource exhaustion by limiting request frequency and header size. Use tower-based crates such as tower-http for rate limiting and configure Axum’s extractors to reject oversized headers:
use axum::{routing::get, Router};
use tower_http::limit::RequestBodyLimitLayer;
use tower_http::set_header::SetResponseHeaderLayer;
use tower_http::throttle::{Throttle, ThrottleLayer};
use std::time::Duration;
fn build_app() -> Router {
// Limit request body size to mitigate large header attacks
let request_limit = RequestBodyLimitLayer::new(1024 * 64); // 64 KiB
// Throttle to 10 requests per second per IP
let throttle = ThrottleLayer::new(
tower_http::throttle::Rate::new(10, Duration::from_secs(1)),
tower_http::throttle::key::RemoteAddr.into(),
);
// Optionally set security headers
let headers = SetResponseHeaderLayer::overriding(
axum::http::HeaderName::from_static("x-content-type-options"),
axum::http::HeaderValue::from_static("nosniff"),
);
Router::new()
.route("/api/me", get(|| async { "ok" }))
.layer(request_limit)
.layer(throttle)
.layer(headers)
}
3. Validate and sanitize Authorization headers
Reject malformed or suspiciously large headers before processing. You can add a middleware or request guard that checks header length and rejects non-ASCII or abnormally long values to reduce parsing overhead and potential memory spikes.
By combining lightweight validation, caching, rate limiting, and input size enforcement, you mitigate DoS vectors while retaining Basic Auth’s simplicity. middleBrick’s scan can verify that these controls are present by checking for rate limiting and authentication configurations in your unauthenticated attack surface tests.
Related CWEs: resourceConsumption
| CWE ID | Name | Severity |
|---|---|---|
| CWE-400 | Uncontrolled Resource Consumption | HIGH |
| CWE-770 | Allocation of Resources Without Limits | MEDIUM |
| CWE-799 | Improper Control of Interaction Frequency | MEDIUM |
| CWE-835 | Infinite Loop | HIGH |
| CWE-1050 | Excessive Platform Resource Consumption | MEDIUM |