Missing Tls in Axum with Basic Auth
Missing Tls in Axum with Basic Auth — how this specific combination creates or exposes the vulnerability
Transport Layer Security (TLS) is the baseline network protection that encrypts traffic between clients and servers. When an Axum service that uses HTTP Basic Authentication does not enforce TLS, credentials and session tokens are transmitted as base64-encoded plaintext. Base64 is not encryption; it is an encoding scheme that provides no confidentiality. An attacker who can observe or intercept network traffic—such as on shared Wi‑Fi, through a compromised router, or via a misconfigured proxy—can trivially decode the Authorization header and recover the username and password.
In a black-box scan, middleBrick checks whether endpoints that accept credentials advertise and require TLS by inspecting whether requests to http:// endpoints redirect to https:// and whether credentials are transmitted over unencrypted channels. For Axum services, middleBrick tests the unauthenticated attack surface and flags Missing TLS when credentials are accepted over non-TLS connections. This becomes especially high-risk when Basic Auth is used, because the secret is not bound to a secure channel and is static across requests. Unlike token-based mechanisms that can be rotated and scoped, Basic Auth credentials are long-lived and widely supported, making them attractive targets for passive sniffing and replay attacks.
The risk is further compounded when services are exposed on common ports without explicit enforcement of secure endpoints. MiddleBrick’s checks for Data Exposure and Encryption identify whether responses contain sensitive data and whether the transport appears encrypted. An Axum application that exposes a login route or a protected resource over HTTP while claiming to use Basic Auth will receive a severe finding, because an attacker can harvest credentials and reuse them in subsequent requests to the same service, potentially bypassing other application-level checks.
Basic Auth-Specific Remediation in Axum — concrete code fixes
To secure Axum services using HTTP Basic Authentication, you must enforce TLS on all endpoints that handle credentials and avoid transmitting secrets over plaintext HTTP. Below are concrete, realistic code examples that demonstrate a secure approach.
1. Enforce HTTPS with a redirect from HTTP
Ensure your Axum service listens only on HTTPS or redirects HTTP to HTTPS before any authentication logic runs. In practice, this is often done at the load balancer or reverse proxy (e.g., Nginx, Caddy, or cloud load balancer). If you handle it in Rust, you can provide a separate HTTP listener that issues 301 redirects.
use axum::{Router, routing::get, response::Redirect};
async fn redirect_to_https() -> Redirect {
Redirect::permanent("https://api.example.com/")
}
fn insecure_router() -> Router {
Router::new().route("/", get(redirect_to_https))
}
This ensures that clients reaching http://api.example.com are immediately directed to the secure endpoint, reducing the window for credential exposure.
2. Require TLS and validate the request scheme
Within your Axum application, you can add a layer that rejects or warns when the request is not secure. While Axum does not provide built-in HTTPS-only enforcement, you can inspect the request’s URI and headers and return a 400 or 403 if the scheme is not https.
use axum::{Router, routing::get, response::IntoResponse, extract::Request, http::StatusCode};
async fn secure_handler() -> &'static str {
"OK over TLS"
}
async fn require_https(request: Request, next: axum::routing::get::Handler<_, _>) -> impl IntoResponse {
if request.uri().scheme_str() != Some("https") {
return (StatusCode::FORBIDDEN, "HTTPS required");
}
next.run(request).await
}
fn secure_router() -> Router {
Router::new()
.route("/login", get(require_https))
}
This approach makes it explicit that credentials are only accepted over encrypted channels.
3. Provide correct Basic Auth examples over HTTPS
When you do implement Basic Auth, ensure the credentials are only verified after confirming the transport is secure. The following example shows a typical extractor that checks a static username/password pair while assuming HTTPS is enforced upstream.
use axum::{Router, routing::get, extract::Extension, http::HeaderMap};
use std::net::SocketAddr;
use tower_http::auth::{AuthLayer, Credentials, ServiceAuthentication};
use tower_http::auth::authorization::{BearerAuthorization, Authorization};
#[tokio::main]
async fn main() {
// In production, terminate TLS at the proxy or use a TLS acceptor.
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let auth_layer = AuthLayer::basic(authenticate);
let app = Router::new()
.route("/profile", get(|| async { "Secure profile" }))
.layer(auth_layer);
// Note: Use a proper TLS acceptor or reverse proxy in production.
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn authenticate(credentials: Credentials) -> Result<(), &'static str> {
const USER: &str = "admin";
const PASS: &str = "correct horse battery staple";
if credentials.user == USER && credentials.pass == PASS {
Ok(())
} else {
Err("Invalid credentials")
}
}
Note that the example does not implement TLS itself; it assumes TLS termination happens outside the service. This mirrors best practice where TLS is handled by a load balancer or reverse proxy, while Axum focuses on application logic.
4. Complementary protections
Combine TLS enforcement with other security headers and rate limiting to reduce the impact of any residual exposure. While middleBrick’s checks for Rate Limiting and Input Validation do not replace transport security, they help build a defense-in-depth posture around the Basic Auth flow.
Related CWEs: encryption
| CWE ID | Name | Severity |
|---|---|---|
| CWE-319 | Cleartext Transmission of Sensitive Information | HIGH |
| CWE-295 | Improper Certificate Validation | HIGH |
| CWE-326 | Inadequate Encryption Strength | HIGH |
| CWE-327 | Use of a Broken or Risky Cryptographic Algorithm | HIGH |
| CWE-328 | Use of Weak Hash | HIGH |
| CWE-330 | Use of Insufficiently Random Values | HIGH |
| CWE-338 | Use of Cryptographically Weak PRNG | MEDIUM |
| CWE-693 | Protection Mechanism Failure | MEDIUM |
| CWE-757 | Selection of Less-Secure Algorithm During Negotiation | HIGH |
| CWE-261 | Weak Encoding for Password | HIGH |