Session Fixation in Actix with Firestore
Session Fixation in Actix with Firestore — how this specific combination creates or exposes the vulnerability
Session fixation occurs when an application accepts a session identifier provided by the client without verifying that the session was established by the server. In an Actix web application using Firestore as the session store, this typically arises when session identifiers are created or accepted in URLs, form parameters, or headers without server-side assignment. Firestore documents that represent sessions may contain fields such as user_id, created_at, and last_active, but if the session ID is supplied by the client and directly used to read or write those documents, the server may trust the client-supplied identifier.
Consider an Actix service that reads session data from a Firestore collection named sessions. If the client can provide the document ID used to retrieve session state, an attacker can fixate that ID on the victim’s browser and later reuse it after authentication. For example, a route that accepts a session ID via query parameter and then reads from Firestore without server-generated randomness enables fixation:
async fn get_session(session_id: web::Path, firestore: web::Data) -> impl Responder {
let doc_ref = firestore.collection("sessions").doc(&session_id).get().await;
// process session
}
Because the document ID is directly derived from client input, an attacker can craft a URL like https://api.example.com/session/ATTACKER_SESSION_ID and trick a victim into visiting it. If the victim authenticates later, the attacker can use the same session ID to impersonate the victim. This pattern is common when session identifiers are exposed in URLs or when the server does not rotate identifiers after authentication.
The risk is compounded when Firestore security rules are misconfigured, allowing read/write access to session documents based solely on document ID without additional ownership checks. An attacker may also probe for predictable IDs or leverage leaked session tokens from other sources to access or modify session documents. Because the application treats client-supplied IDs as authoritative, the trust boundary is violated, enabling session hijacking or privilege escalation.
middleBrick’s unauthenticated scans can detect endpoints that accept session identifiers from client-controlled sources and reference Firestore document reads/writes without server-side session initialization. By analyzing OpenAPI specs and runtime behavior, the scanner highlights endpoints where session identifiers are not generated or rotated by the server, mapping findings to relevant OWASP API Top 10 and authentication-related checks.
Firestore-Specific Remediation in Actix — concrete code fixes
To remediate session fixation in Actix with Firestore, ensure that session identifiers are generated server-side using cryptographically random values and never derived from or directly controlled by the client. Use secure, HTTP-only cookies for session transmission and rotate the session identifier after successful authentication.
Below is a secure Actix handler that creates a new session with a server-generated ID and stores it in Firestore. It uses the uuid crate for randomness and sets a secure cookie:
use actix_web::{web, HttpResponse, Cookie};
use uuid::Uuid;
async fn create_session(user_id: String, firestore: web::Data) -> HttpResponse {
let session_id = Uuid::new_v4().to_string();
let session_data = json!({
"user_id": user_id,
"created_at": chrono::Utc::now().to_rfc3339(),
"last_active": chrono::Utc::now().to_rfc3339()
});
firestore.collection("sessions").doc(&session_id)
.set(session_data)
.await
.expect("Failed to create session in Firestore");
let mut resp = HttpResponse::Ok().finish();
resp.add_cookie(&Cookie::build(("session_id", session_id))
.http_only(true)
.secure(true)
.same_site(actix_web::cookie::SameSite::Strict)
.path("/")
.max_age(time::Duration::hours(1))
.finish()).expect("Failed to add cookie");
resp
}
On subsequent authenticated requests, the server should read the session ID from the cookie, not from URL parameters or headers controlled by the client. Validate that the session document exists in Firestore and enforce ownership checks using additional fields such as user_id or permissions. For example:
async fn validate_session(cookie_req: &HttpRequest, firestore: web::Data) -> bool {
let cookie = cookie_req.cookie("session_id");
match cookie {
Some(c) => {
let session_id = c.value();
let doc = firestore.collection("sessions").doc(session_id).get().await;
if let Ok(doc) = doc {
if let Some(uid) = doc.get::("user_id") {
// additional checks: expiration, revocation, etc.
return true;
}
}
false
}
None => false,
}
}
Rotate the session identifier after authentication to prevent fixation. Issue a new session ID and replace the cookie while invalidating the old Firestore document or marking it as deprecated. Also ensure Firestore security rules require ownership checks (e.g., matching user_id) rather than allowing unrestricted access based on document ID alone.
middleBrick’s Pro plan enables continuous monitoring for endpoints that handle session tokens and Firestore interactions. With GitHub Action integration, you can fail builds if insecure session handling patterns are detected in API specs or scans, and the dashboard tracks security scores over time to highlight improvements after remediation.