Session Fixation in Actix with Hmac Signatures
Session Fixation in Actix with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Session fixation occurs when an application forces a user to use a known, attacker-controlled session identifier. In Actix applications that use Hmac Signatures for session integrity, fixation can arise if the server accepts an incoming session token (e.g., from a URL query parameter or a non-HttpOnly cookie) and then reuses it to derive a signed session without re-keying or binding it to a post-authentication context.
With Hmac Signatures, the server typically signs session data (such as user ID, role, or session metadata) using a server-side secret. If an attacker sets or guesses a session token before authentication and the server later signs that same token without verifying that it was freshly issued post-login, the attacker can impersonate the victim by coercing them to use the pre-agreed token. This is a classic session fixation vector that leverages trust in the Hmac signature rather than a new, server-issued identifier.
In Actix, this can surface when session state is read from request data (cookies, headers, or query parameters) and directly passed to a signing function without validating provenance. For example, if an endpoint accepts a session_id from the query string and then constructs a signed payload using that ID, an attacker can craft a URL like https://api.example.com/action?session_id=attacker123. After the victim authenticates, the server signs attacker123 as a valid session, allowing the attacker to hijack the authenticated session.
The risk is compounded if the Hmac scheme does not include contextual binding such as the client’s IP, a per-request nonce, or a timestamp with tight tolerance. Without these, the signature remains valid across contexts, making fixation and replay more feasible. middleBrick’s LLM/AI Security checks and authentication testing help surface cases where untrusted input directly influences signed session material, which is a key indicator of potential fixation in API security scans.
Hmac Signatures-Specific Remediation in Actix — concrete code fixes
To remediate session fixation with Hmac Signatures in Actix, ensure that any session token used for signing is issued by the server after successful authentication and is not directly derived from attacker-controlled input. Bind the signature to post-login context and include additional verifiers such as a user-specific secret or timestamp.
Use HttpOnly, Secure cookies for session storage and avoid accepting session identifiers from query parameters or mutable headers. When signing, incorporate a per-session nonce or timestamp and validate freshness on each request. Below are two concrete Actix examples: one vulnerable pattern and one hardened implementation.
Vulnerable pattern (do not use)
use actix_web::{web, HttpResponse};
use hmac::{Hmac, Mac};
use sha2::Sha256;
type HmacSha256 = Hmac;
// Vulnerable: accepts session_id from query and signs it directly
async fn login_vulnerable(query: web::Query>) -> HttpResponse {
let session_id = query.get("session_id").cloned().unwrap_or_else(|| "default".to_string());
let mut mac = HmacSha256::new_from_slice(b"super-secret-key").expect("HMAC can take key of any size");
mac.update(session_id.as_bytes());
let result = mac.finalize();
let signature = result.into_bytes();
// Further logic to set cookie or token
HttpResponse::Ok().body(format!("signed: {:x?}", signature))
}
Hardened implementation
use actix_web::{cookie::Cookie, web, HttpResponse};
use hmac::{Hmac, Mac};
use sha2::Sha256;
use uuid::Uuid;
use std::time::{SystemTime, UNIX_EPOCH};
type HmacSha256 = Hmac;
// Hardened: server-issued session after auth, with nonce and timestamp
async fn login_hardend(user_id: String) -> (String, String) {
let session_id = Uuid::new_v4().to_string(); // server-issued
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs().to_string();
let nonce = Uuid::new_v4().to_string();
let data_to_sign = format!("{}:{}:{}", session_id, timestamp, nonce);
let mut mac = HmacSha256::new_from_slice(b"super-secret-key").expect("HMAC can take key of any size");
mac.update(data_to_sign.as_bytes());
let signature = mac.finalize().into_bytes();
let sig_hex = format!("{:x}", signature);
// Store session_id, timestamp, nonce server-side (e.g., in a KV store) and send cookie
let cookie = Cookie::build(("session", session_id))
.http_only(true)
.secure(true)
.same_site(actix_web::cookie::SameSite::Strict)
.finish();
// In practice, enqueue cookie via response
(session_id, sig_hex)
}
async fn verify_hardend(session_id: String, timestamp: String, nonce: String, received_sig: String) -> bool {
let data_to_sign = format!("{}:{}:{}", session_id, timestamp, nonce);
let mut mac = HmacSha256::new_from_slice(b"super-secret-key").expect("HMAC can take key of any size");
mac.update(data_to_sign.as_bytes());
let expected_sig = mac.finalize().into_bytes();
let expected_hex = format!("{:x}", expected_sig);
// Constant-time compare in production
expected_hex == received_sig
}
Key practices:
- Generate session IDs server-side (e.g., UUIDv4) after authentication; never trust client-provided values for signing inputs.
- Include a timestamp and a cryptographically random nonce in the signed payload and validate freshness on each request to prevent replay and fixation.
- Use HttpOnly, Secure, SameSite cookies for session transmission and avoid exposing session identifiers in URLs or mutable headers.
- Store minimal session metadata server-side and keep only a non-sensitive reference (e.g., session ID) in the cookie; validate the binding on each request.
These steps reduce the attack surface for session fixation and ensure that Hmac-signed sessions remain tied to authenticated, server-controlled contexts.