Session Fixation in Actix
How Session Fixation Manifests in Actix
Session fixation in Actix occurs when an attacker sets a session identifier on a victim's browser before authentication, then the server accepts this pre-set ID after the victim logs in. This allows the attacker to hijack the session by using the same session ID.
In Actix, this typically manifests through improper session ID generation or reuse. The default actix-web::cookie::Session middleware generates cryptographically secure session IDs, but developers often create custom session handling that introduces vulnerabilities.
Common Actix-specific patterns that enable session fixation:
- Using predictable session IDs (like incrementing counters or timestamps)
- Storing session data in client-side cookies without server-side validation
- Accepting session IDs from query parameters or headers
- Creating new sessions without destroying old ones during authentication
- Using non-cryptographically secure random number generators
Here's a vulnerable Actix pattern:
async fn login(mut req: HttpRequest, form: Form) -> impl Responder {
let user = authenticate(form.username, form.password).await;
if let Some(user) = user {
// VULNERABLE: session ID remains unchanged after login
let session = Session::get(&req);
session.set("user_id", user.id);
session.set("authenticated", true);
return HttpResponse::Found()
.insert_header((http::header::LOCATION, "/dashboard"))
.finish();
}
HttpResponse::BadRequest().body("Invalid credentials")
}
This code accepts whatever session ID the client presents and simply marks it as authenticated. An attacker could set a session ID via a crafted link, have the victim click it, and then hijack the session after login.
Another Actix-specific vulnerability occurs when using actix-session with custom session stores that don't properly validate session IDs:
use actix_session::Session;
async fn vulnerable_handler(
session: Session,
query: web::Query<MyQuery>,
) -> impl Responder {
// VULNERABLE: accepting session ID from query parameter
if let Some(sid) = query.session_id {
session.set_session_id(sid);
}
// ... rest of handler
}
This pattern allows attackers to specify arbitrary session IDs, completely bypassing Actix's session security mechanisms.
Actix-Specific Detection
Detecting session fixation in Actix applications requires examining both code patterns and runtime behavior. Here are Actix-specific detection methods:
Code Analysis: Look for these patterns in your Actix codebase:
// Dangerous patterns to search for:
// 1. Custom session ID generation without crypto randomness
let session_id = format!("sess_{}", rand::thread_rng().gen::());
// 2. Accepting session IDs from client-controlled sources
if let Some(sid) = req.headers().get("X-Session-ID") { ... }
// 3. Not regenerating session IDs on authentication
// (missing call to session.reset() or equivalent)
Runtime Testing: Test your Actix application by:
- Creating a session before authentication
- Authenticating with that session ID
- Verifying the session ID remains unchanged
Using middleBrick Scanner: The middleBrick API security scanner specifically tests for session fixation vulnerabilities in Actix applications. It:
- Attempts to create sessions before authentication
- Tests if session IDs persist across authentication boundaries
- Checks for predictable session ID patterns
- Verifies proper session invalidation on logout
middleBrick's Actix-specific checks include:
$ middlebrick scan https://your-actix-app.com
=== Session Security ===
✓ Session ID randomness: PASS (cryptographically secure)
✗ Session fixation: FAIL (session ID persists after authentication)
✓ Session invalidation: PASS
Risk Score: C (72/100)
Recommendation: Regenerate session ID upon authentication
The scanner tests the unauthenticated attack surface of your Actix application in 5-15 seconds without requiring credentials or configuration. It specifically looks for Actix's session handling patterns and identifies where session fixation vulnerabilities exist.
Middleware Inspection: Examine your Actix middleware chain for custom session handling:
app.wrap(
SessionMiddleware::new(
CookieSessionStore::default(),
CookieSessionConfig::default()
.cookie_secure(false) // dangerous in production
.cookie_same_site(SameSite::None)
)
);
Pay special attention to middleware that modifies session behavior or accepts client-provided session identifiers.
Actix-Specific Remediation
Fixing session fixation in Actix requires proper session lifecycle management. Here are Actix-specific remediation techniques:
1. Regenerate Session IDs on Authentication:
use actix_session::Session;
async fn secure_login(
mut req: HttpRequest,
form: Form<Login>,
session: Session,
) -> impl Responder {
let user = authenticate(form.username, form.password).await;
if let Some(user) = user {
// CRITICAL: regenerate session ID to prevent fixation
session.reset();
session.set("user_id", user.id);
session.set("authenticated", true);
return HttpResponse::Found()
.insert_header((http::header::LOCATION, "/dashboard"))
.finish();
}
HttpResponse::BadRequest().body("Invalid credentials")
}
The session.reset() call destroys the old session and creates a new one, breaking any session fixation attack chain.
2. Use Secure Session Configuration:
use actix_session::{SessionMiddleware, CookieSessionStore};
use actix_session::config::CookieSessionConfig;
let session_config = CookieSessionConfig::default()
.cookie_secure(true) // HTTPS only
.cookie_http_only(true) // prevents JS access
.cookie_same_site(actix_session::config::SameSite::Lax)
.cookie_path("/")
.cookie_name("secure_session");
app.wrap(
SessionMiddleware::new(
CookieSessionStore::default(),
session_config
)
);
3. Implement Proper Session Invalidation:
async fn logout(mut req: HttpRequest, session: Session) -> impl Responder {
// Destroy session completely
session.purge();
// Also clear the session cookie
if let Some(cookies) = req.headers().get_all(http::header::COOKIE) {
for cookie in cookies {
if let Ok(cookie_str) = cookie.to_str() {
if cookie_str.contains("secure_session=") {
// Remove session cookie
return HttpResponse::Found()
.insert_header((http::header::LOCATION, "/"))
.insert_header(
(http::header::SET_COOKIE, "secure_session=deleted; Path=/; Max-Age=0")
)
.finish();
}
}
}
}
HttpResponse::Found()
.insert_header((http::header::LOCATION, "/"))
.finish()
}
4. Add Session Validation Middleware:
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, HttpMessage};
use actix_session::Session;
#[derive(Clone)]
struct SessionFixationPrevention;
impl Transform for SessionFixationPrevention
where
S: Service, Error = actix_web::Error>,
{
type Response = ServiceResponse;
type Error = actix_web::Error;
type InitError = ();
type Transform = SessionFixationPreventionMiddleware;
fn new_transform(&self, service: S) -> Result {
Ok(SessionFixationPreventionMiddleware { service })
}
}
struct SessionFixationPreventionMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for SessionFixationPreventionMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>>,
{
type Response = ServiceResponse<B>;
type Error = actix_web::Error;
type Future = actix_web::dev::Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut std::task::Context) -> std::task::Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
// Check if session ID looks suspicious (e.g., predictable pattern)
if let Some(session) = Session::get(&req) {
if let Ok(sid) = session.get_session_id() {
// Example: reject session IDs that look sequential
if sid.starts_with("sess_") && sid.len() < 20 {
// Force session reset for suspicious IDs
session.reset();
}
}
}
actix_web::dev::ready(Ok(self.service.call(req).await?))
}
}
5. Continuous Monitoring with middleBrick:
Integrate middleBrick into your Actix development workflow:
# Install CLI
npm install -g middlebrick
# Scan your Actix API
middlebrick scan https://your-actix-app.com/api
# In CI/CD (GitHub Action)
- name: Run middleBrick Security Scan
uses: middlebrick/middlebrick-action@v1
with:
api_url: https://your-actix-app.com
fail_below_score: 80
token: ${{ secrets.MIDDLEBRICK_TOKEN }}
middleBrick continuously monitors your Actix application for session fixation and other API security issues, providing actionable remediation guidance specific to Actix's session handling patterns.
Frequently Asked Questions
Does Actix's default session middleware protect against session fixation?
Actix's default session middleware provides a foundation but doesn't automatically prevent session fixation. The middleware generates cryptographically secure session IDs, but developers must explicitly regenerate session IDs upon authentication using session.reset(). Without this step, an attacker can still fixate a session ID before login and maintain access after authentication.
How can I test my Actix application for session fixation vulnerabilities?
Test by creating a session before authentication, then authenticating with that same session ID. If the session ID remains unchanged, you have a vulnerability. Use middleBrick's automated scanner to test this and other session security issues. The scanner specifically checks Actix session handling patterns and provides a security risk score with remediation guidance. You can also manually inspect your code for patterns that accept client-provided session IDs or fail to regenerate session IDs on authentication.