Dictionary Attack in Axum with Basic Auth
Dictionary Attack in Axum with Basic Auth — how this specific combination creates or exposes the vulnerability
A dictionary attack against an Axum endpoint protected with HTTP Basic Auth leverages two factors: the simplicity of the authentication mechanism and the absence of rate-limiting or other anti-automation controls. Basic Auth encodes credentials in Base64 (not encryption) and transmits them on every request; if an attacker enumerates common username and password pairs, they can systematically attempt authentication until a valid pair is found. Axum does not inherently throttle authentication attempts at the framework level, so an unauthenticated attacker can submit many requests rapidly, making credential guessing feasible.
Because middleBrick tests unauthenticated attack surfaces, it can detect whether an endpoint accepts repeated authentication probes and whether responses differ in a way that reveals valid usernames (e.g., 200 versus 401). In a real scan, middleBrick runs checks that look for weak account policies, predictable credential paths, and missing protections such as account lockout or exponential backoff. When combined with the BFLA/Privilege Escalation and Authentication checks, a dictionary attack against Basic Auth can expose endpoints where weak credentials lead to unauthorized access, potentially enabling attackers to bypass intended access controls entirely.
From a specification perspective, if an OpenAPI/Swagger definition declares securitySchemes of type http with scheme basic but does not enforce additional constraints (such as rate limits or required MFA), the scan will highlight the gap between declared security and runtime behavior. This misalignment is a common root cause for findings mapped to OWASP API Top 10:2023 —2 – Broken Authentication. middleBrick also maps findings to frameworks like PCI-DSS and SOC2, where weak authentication controls are treated as high-risk observations.
Basic Auth-Specific Remediation in Axum — concrete code fixes
Remediation focuses on strengthening authentication and reducing the effectiveness of dictionary attacks. Replace Basic Auth with token-based authentication where possible, or enforce strict protections around Basic Auth. Below are concrete Axum examples that implement middleware to enforce strong credentials and rate-limiting, reducing the attack surface.
First, an Axum route using a more secure approach with a hardcoded user and constant-time comparison to mitigate timing attacks:
use axum::{routing::get, Router};
use axum::http::header;
use axum::extract::Request;
use axum::middleware::Next;
use std::convert::Infallible;
use std::net::SocketAddr;
use tower_http::services::ServeDir;
const VALID_USER: &str = "admin";
const VALID_PASS_HASH: &str = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"; // sha256 of "password"
async fn validate_basic_auth(req: Request, next: Next) -> Result<Response, (StatusCode, String)> {
if let Some(auth_header) = req.headers().get(header::AUTHORIZATION) {
if let Ok(auth_str) = auth_header.to_str() {
if auth_str.starts_with("Basic ") {
let encoded = &auth_str[6..];
if let Ok(decoded) = base64::decode(encoded) {
if let Ok(credentials) = String::from_utf8(decoded) {
let parts: Vec<&str> = credentials.splitn(2, ':').collect();
if parts.len() == 2 {
let (user, pass) = (parts[0], parts[1]);
// Use constant-time comparison for password hash
let pass_hash = sha256::digest(pass);
if subtle::ConstantTimeEq::ct_eq(&pass_hash.as_bytes(), VALID_PASS_HASH.as_bytes()).into() {
return Ok(next.run(req).await);
}
}
}
}
}
}
}
Err((StatusCode::UNAUTHORIZED, "Unauthorized".to_string()))
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/secure", get(|| async { "OK" }))
.layer(axum::middleware::from_fn(validate_basic_auth));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
Second, integrate a rate-limiting middleware such as tower::limit::RateLimitLayer to throttle repeated attempts:
use tower_http::limit::RateLimitLayer;
use std::time::Duration;
let app = Router::new()
.route("/secure", get(|| async { "OK" }))
.layer(RateLimitLayer::new(10, Duration::from_secs(1))); // 10 requests per second
These changes reduce the risk of successful dictionary attacks by ensuring credentials are not easily guessable and by limiting the rate at which attempts can be made. middleBrick scans can verify that such protections are present and flag endpoints that still accept high-rate authentication attempts without safeguards.