Cryptographic Failures in Axum with Basic Auth
Cryptographic Failures in Axum with Basic Auth — how this specific combination creates or exposes the vulnerability
Basic Auth transmits credentials as a Base64-encoded string in the Authorization header. Base64 is not encryption; it is easily reversible, so any party that intercepts the header can recover the username and password. In Axum, if an endpoint is configured to accept Basic Auth but is served over HTTP (non-TLS), the credentials are exposed in cleartext across the network. Even when TLS is used, misconfiguration can weaken protections, for example by allowing weak cipher suites or outdated protocol versions that make session interception feasible (e.g., via protocols susceptible to downgrade or known TLS implementation bugs).
Cryptographic failures also arise from how credentials are handled after extraction. If Axum handlers or middleware store the decoded credentials in logs, caches, or error messages, they may be exposed in log files or to unauthorized users on the host. Hardcoding credentials in source code or configuration files checked into version control is another common pitfall; these artifacts can be leaked through repository history or accidental exposure. MiddleBrick’s unauthenticated scan detects such issues by checking whether authentication is absent or trivially bypassed and by correlating spec definitions with runtime behavior to highlight weak or missing protections.
In practice, a scan might flag endpoints that accept Basic Auth but lack sufficient transport protections, or that expose authentication-related metadata in responses. These findings map to OWASP API Top 10 cryptographic weaknesses and can intersect with risks such as insecure data exposure and insufficient encryption. MiddleBrick’s cross-referencing of OpenAPI/Swagger specs (including $ref resolution) with runtime observations ensures that discrepancies—such as documented HTTPS requirements that are not enforced—are surfaced as actionable findings with remediation guidance.
Basic Auth-Specific Remediation in Axum — concrete code fixes
To mitigate cryptographic failures with Basic Auth in Axum, enforce TLS for all traffic, avoid logging credentials, and validate the Authorization header securely. Below are concrete, working examples that you can adapt to your Axum service.
1. Require TLS and enforce secure transport
Ensure your server is only reachable over HTTPS. In practice, this is done at the load balancer or reverse proxy (e.g., using TLS termination with strong cipher suites). In Axum, you can enforce HTTPS by redirecting HTTP requests:
use axum::{Router, routing::get, http::StatusCode};
use std::net::SocketAddr;
async fn redirect_to_https() -> (StatusCode, &'static str) {
(StatusCode::PERMANENT_REDIRECT, "https://your-domain.com/your-endpoint")
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/health", get(|| async { "ok" }))
.layer(axum::middleware::from_fn(|_, next| async move {
// Middleware to redirect non-TLS requests (simplified example)
let is_secure = true; // Determine via headers or connection info in real use
if !is_secure {
return Ok(redirect_to_https().into_response());
}
next.run().await
}));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
2. Securely decode and handle Basic Auth credentials
Use Axum extractors to parse the Authorization header, and ensure credentials are not logged. Avoid storing passwords in plain text; prefer checking against a secure hash or using a constant-time comparison where applicable.
use axum::{Router, routing::get, extract::Request, http::header};
use tower_http::auth::{AuthLayer, AuthBearer, AsyncAuthenticator};
use std::convert::Infallible;
use serde::Deserialize;
#[derive(Deserialize)]
struct Credentials {
username: String,
password: String,
}
async fn validate_credentials(creds: Credentials) -> bool {
// Validate against a secure store or hashed value
// Example: constant-time comparison and/or token generation
creds.username == "valid_user" && creds.password == "correct_hashed_password"
}
async fn handler() -> &'static str {
"authenticated"
}
async fn auth_layer_builder() -> AuthLayer<impl AsyncAuthenticator<Error = Infallible>> {
let auth_fn = |authorization: String| -> async move {
// Basic Auth format: "Basic base64(credentials)"
if let Some(encoded) = authorization.strip_prefix("Basic ") {
if let Ok(decoded_bytes) = base64::decode(encoded) {
if let Ok(credentials_str) = String::from_utf8(decoded_bytes) {
let parts: Vec<&str> = credentials_str.split(':').collect();
if parts.len() == 2 {
let creds = Credentials {
username: parts[0].to_string(),
password: parts[1].to_string(),
};
if validate_credentials(creds).await {
return Ok(AuthBearer::Authorized(creds.username));
}
}
}
}
}
Err(()) // Reject invalid/missing credentials
};
AuthLayer::new(auth_fn)
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/secure", get(handler).layer(auth_layer_builder()));
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
3. Avoid logging or exposing credentials
Ensure middleware and handlers do not inadvertently log the Authorization header or decoded credentials. Configure logging filters to exclude sensitive headers:
use axum::middleware::Next;
use axum::extract::Request;
use std::future::Future;
async fn no_creds_log_middleware(req: Request, next: Next<B>) -> axum::response::Response {
// Redact sensitive headers before logging
let headers = req.headers();
if let Some(auth) = headers.get(header::AUTHORIZATION) {
tracing::info!(target: "audit", "Authorization header present: [redacted]");
}
next.run(req).await
}
Combine these practices with regular scans from tools like MiddleBrick to detect weak authentication configurations and cryptographic handling issues. MiddleBrick’s findings include remediation steps and map to frameworks such as OWASP API Top 10 and PCI-DSS, helping you prioritize fixes.