Session Fixation in Actix with Api Keys
Session Fixation in Actix with Api Keys — how this specific combination creates or exposes the vulnerability
Session fixation occurs when an application assigns a user a session identifier before authentication and fails to issue a new identifier after login. In Actix applications that rely on API keys for authentication, this pattern can inadvertently tie a fixed session or token to an unauthenticated or partially authenticated context, enabling an attacker to force a known key onto a victim’s session.
Consider an Actix service where API keys are accepted via an HTTP header (e.g., X-API-Key) and used to identify permissions or associate requests with a session. If the server uses the same key value across authenticated and unauthenticated endpoints without rotating or revalidating the key context, an attacker can craft a link containing a known API key. When the victim uses the link, the server may treat the key as the victim’s authenticated credential, leading to unauthorized access to the victim’s resources. This is a session fixation risk specific to API-key-based schemes because the key itself functions as a session token.
For example, an endpoint that retrieves user profile data might simply check for a valid API key without ensuring the key maps to a post-authentication session state. If the key is static or long-lived and reused across different session contexts, an attacker can leverage a key obtained from a shared source (e.g., logs, misconfigured CI) to fix a victim’s session. Because Actix does not inherently rotate the authentication context when a key is presented, the server may continue to treat the key as authoritative without additional validation, enabling the attacker to act as the victim.
In a black-box scan by middleBrick, such misconfigurations appear as findings in the Authentication and BOLA/IDOR checks. The scanner tests whether an API key accepted before authentication remains valid after authentication and whether key reuse across session boundaries exposes fixed session contexts. These findings align with the OWASP API Top 10 category for Broken Object Level Authorization and Authentication weaknesses.
Api Keys-Specific Remediation in Actix — concrete code fixes
Remediation focuses on ensuring that API keys are treated as credentials that must be revalidated after authentication and never reused across distinct session contexts. In Actix, this means explicitly validating key ownership on each request and avoiding implicit trust in keys that were established in an unauthenticated state.
Below is a secure Actix example that demonstrates key validation with explicit ownership checks. The middleware verifies the API key against a data store and ensures the key is bound to the authenticated user context before allowing access to protected endpoints.
use actix_web::{web, App, HttpResponse, HttpServer, Responder, dev::ServiceRequest};
use actix_web::http::header::HeaderValue;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
#[derive(Clone)]
struct AppState {
// Maps API key to user ID
api_keys: Arc>>,
}
async fn validate_key(
req: ServiceRequest,
state: web::Data,
) -> Result {
let key = match req.headers().get("X-API-Key") {
Some(v) => v.to_str().map_err(|_| {
(actix_web::error::ErrorUnauthorized("Invalid key format"), req)
})?,
None => return Err((actix_web::error::ErrorUnauthorized("Missing key"), req)),
};
let keys = state.api_keys.lock().unwrap();
let user_id = keys.get(key).cloned().ok_or_else(|| {
actix_web::error::ErrorUnauthorized("Invalid key")
})?;
// Attach user identity to request extensions for downstream handlers
req.extensions_mut().insert(user_id);
Ok(req)
}
async fn profile_handler(req: ServiceRequest) -> impl Responder {
// The user ID is guaranteed to be present after validation middleware
if let Some(user_id) = req.extensions().get::() {
HttpResponse::Ok().body(format!("Profile for user: {}", user_id))
} else {
HttpResponse::Unauthorized().body("Unauthorized")
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let mut keys = HashMap::new();
keys.insert("trusted-key-123".to_string(), "user-abc".to_string());
let state = web::Data::new(AppState {
api_keys: Arc::new(Mutex::new(keys)),
});
HttpServer::new(move || {
App::new()
.app_data(state.clone())
.wrap_fn(|req, srv| {
let state = req.app_data::>().unwrap().clone();
validate_key(req, state).and_then(|req| srv.call(req))
})
.route("/profile", web::get().().to(profile_handler))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Key remediation practices include:
- Treat API keys as opaque credentials and validate them on every request.
- Bind keys to a specific user or role and re-check ownership in each handler or via guard functions.
- Do not allow keys established before authentication to persist into authenticated sessions; rotate or reassign keys post-login if your threat model requires it.
- Store keys securely (e.g., hashed in a database) and avoid logging them in plaintext.
These measures reduce the risk of session fixation by ensuring that an API key cannot be fixed into a victim’s session without proper validation and re-authentication checks.