Session Hijacking in Axum
How Session Hijacking Manifests in Axum
Session hijacking in Axum applications typically occurs when an attacker steals or predicts a valid session token, allowing them to impersonate a user. In Axum, this often stems from insecure handling of session cookies or tokens in request extractors. A common pattern involves using axum::extract::State or axum::extract::Extension to manage session state without proper validation, leading to token leakage via logs, error messages, or insecure storage.
For example, consider an Axum handler that extracts a session token from a cookie but fails to validate its integrity or expiration:
use axum::extract::Cookie;
use axum::response::IntoResponse;
async fn profile(Cookie(session_token): Cookie) -> impl IntoResponse {
// Vulnerable: directly uses token without validation
if let Some(user) = get_user_from_token(&session_token).await {
format!("Welcome, {}", user.name)
} else {
(axum::http::StatusCode::UNAUTHORIZED, "Invalid session")
}
}
If the session_token is a simple random string without cryptographic signing (e.g., using rand::random()), it may be predictable or brute-forcible. Additionally, if the token is logged in debug mode or exposed via error responses (e.g., returning the token in a 500 error), it becomes susceptible to theft. Attackers can then use stolen tokens to hijack sessions, especially if the token lacks binding to user properties like IP address or user agent—a property authorization failure that middleBrick detects under its "Property Authorization" check.
Another vector is improper token transmission: if Axum serves session tokens over non-HTTPS connections or sets cookies without the Secure and HttpOnly flags, tokens can be intercepted via MITM attacks or stolen by XSS. middleBrick’s "Encryption" and "Data Exposure" checks flag such misconfigurations during unauthenticated scanning of the API surface.
Axum-Specific Detection
Detecting session hijacking risks in Axum requires examining both code patterns and runtime behavior. middleBrick performs black-box scanning by probing unauthenticated endpoints for signs of weak session management. It tests for token predictability by analyzing cookie values across multiple requests, checks for missing security flags (Secure, HttpOnly, SameSite), and attempts to replay or manipulate tokens to bypass validation.
For instance, middleBrick might send requests like:
GET /api/profile HTTP/1.1
Cookie: session_token=abc123
and then vary the token (e.g., abc124, zzz999) to see if the server accepts it without proper validation—a sign of weak token generation or missing signature checks. It also inspects Set-Cookie headers in responses to verify flags:
Set-Cookie: session_token=abc123; Path=/; HttpOnly
Here, the missing Secure flag would be flagged if the API is served over HTTPS, as the token could be sent over HTTP. middleBrick’s "Input Validation" check detects improper token parsing (e.g., accepting tokens with invalid characters), while its "Authentication" check validates whether endpoints properly enforce session validity.
Developers can also self-audit by reviewing Axum extractors: ensure tokens are validated via cryptographic signatures (e.g., using axum-extra::extract::cookie::PrivateCookieJar with a secret key) and that handlers reject malformed or expired tokens. middleBrick’s CLI (middlebrick scan https://api.example.com) automates this, providing a risk score and specific findings like "Session token missing Secure flag" or "Token validation bypassable via prediction" with remediation guidance.
Axum-Specific Remediation
Fixing session hijacking in Axum involves leveraging its type-safe extractors and secure cookie handling. The primary mitigation is to use PrivateCookieJar from axum-extra to encrypt and sign session cookies, preventing tampering and theft. Never rely on raw cookie values; instead, validate them through Axum’s extractor system.
Replace insecure token extraction with a signed cookie approach:
use axum::extract::State;
use axum_extra::extract::cookie::{PrivateCookieJar, Key};
use axum::response::IntoResponse;
#[derive(Clone)]
struct AppState {
key: Key, // Generated at startup, e.g., Key::generate()
}
async fn profile(
State(state): State,
jar: PrivateCookieJar,
) -> Result<(PrivateCookieJar, impl IntoResponse), (axum::http::StatusCode, PrivateCookieJar)> {
let session_token = jar.get("session_token")
.and_then(|cookie| cookie.value().to_str().ok())
.and_then(|token| validate_token(token));
match session_token {
Some(user_id) => {
let user = get_user(user_id).await;
Ok((jar, format!("Welcome, {}", user.name)))
}
None => {
// Clear invalid token
let jar = jar.remove("session_token");
Err((axum::http::StatusCode::UNAUTHORIZED, jar))
}
}
}
This code uses PrivateCookieJar to automatically decrypt and verify the cookie using the Key stored in AppState. If the token is missing, tampered, or expired, jar.get returns None, triggering an unauthorized response. The cookie is never exposed in raw form to the handler.
Additionally, configure the cookie with secure flags when setting it:
async fn login(/* ... */) -> impl IntoResponse {
let token = generate_secure_token();
let jar = PrivateCookieJar::new(Key::generate());
jar.add(
Cookie::build(("session_token", token))
.path("/")
.secure(true) // Only send over HTTPS
.http_only(true) // Not accessible via JavaScript
.same_site(same_site::SameSite::Strict)
.build(),
);
(jar, "Login successful")
}
These settings prevent token leakage via XSS (HttpOnly) and MITM (Secure), while SameSite=Strict mitigates CSRF-related session risks. middleBrick validates these fixes by rescanning endpoints and confirming that session tokens are now cryptographically protected and properly flagged—improving the "Encryption" and "Property Authorization" scores in its report. Always rotate the Key periodically and store it securely (e.g., via environment variables), never in source code.