HIGH session fixationfastapifirestore

Session Fixation in Fastapi with Firestore

Session Fixation in Fastapi with Firestore — how this specific combination creates or exposes the vulnerability

Session fixation occurs when an application assigns a user a session identifier before authentication and does not rotate or validate that identifier after login. In a Fastapi application using Firestore as the session store, the risk arises from the interaction between Fastapi’s session handling (or lack thereof) and how Firestore documents are created, referenced, and updated.

Consider a scenario where Fastapi issues a session token via a cookie or a custom header, stores minimal identifying data client-side (e.g., a JWT or a plain session ID), and relies on Firestore to validate identity on each request. If the session ID is set before authentication and never reassigned after a successful login, an attacker can craft a URL with a known session ID and trick a victim into authenticating under that ID. Because Firestore documents are often referenced directly by ID (e.g., users/{user_id}/sessions/{session_id}), a predictable or attacker-supplied session ID can lead to unauthorized access when the application trusts that ID without additional binding to the authenticated user’s credentials or context.

Firestore’s security rules and document structure can inadvertently support fixation if rules permit write access to session documents based solely on the session ID without verifying ownership. For example, if a rule allows update or set on a session document path where the user ID is derived from the request body or token rather than enforced server-side, an attacker can authenticate to a pre-existing session and maintain access post-login. Additionally, Fastapi middleware that reads a session ID from cookies or headers and directly queries Firestore without regenerating the session on privilege elevation creates a clear path for exploitation.

Real-world attack patterns include sending a victim a link like https://api.example.com/login?session=attacker_chosen_value and then luring the victim into authenticating. If Fastapi uses the query parameter to set a session cookie and Firestore trusts that value, the victim’s authenticated session will carry the attacker’s chosen identifier. Subsequent requests using that cookie will map to the attacker’s Firestore session document, enabling unauthorized operations such as reading or modifying sensitive user data.

To detect this class of issue, scanning tools evaluate whether session identifiers are generated after authentication, whether they are bound to user-specific data (such as UID or device fingerprint), and whether Firestore rules enforce ownership checks on session document access. MiddleBrick’s checks for BOLA/IDOR and Authentication include validation that session tokens are not predictable or controllable by the client and that authorization is verified on every Firestore read/write, not just at creation time.

Firestore-Specific Remediation in Fastapi — concrete code fixes

Remediation focuses on ensuring session identifiers are assigned only after successful authentication and are bound to immutable user attributes. In Fastapi, avoid relying on client-controlled session IDs and instead generate a server-side, cryptographically random session token upon login. Store this token in Firestore with a document that includes the user’s UID, creation timestamp, and a server-side validation mechanism.

Example: After verifying credentials, create a new session document under the user’s collection with a server-generated ID, and set the session cookie only after confirming the document exists.

from fastapi import Fastapi, Request, Response, HTTPException, Depends
from google.cloud import firestore
import secrets
import datetime

app = Fastapi()
db = firestore.Client()

def get_current_user(request: Request):
    session_token = request.cookies.get("session_token")
    if not session_token:
        raise HTTPException(status_code=401, detail="Missing session token")
    # Validate session token against Firestore
    session_ref = db.collection("sessions")
    # Query by token hash for better security; here simplified for example
    docs = session_ref.where("token", "==", session_token).limit(1).stream()
    for doc in docs:
        session_data = doc.to_dict()
        if session_data["expires_at"] > datetime.datetime.utcnow():
            # Bind session to user ID on each request to prevent fixation
            return {"uid": session_data["uid"], "session_id": doc.id}
    raise HTTPException(status_code=401, detail="Invalid session")

@app.post("/login")
async def login(username: str, password: str, response: Response):
    # Authenticate user (pseudo-check)
    user_ref = db.collection("users").where("username", "==", username).limit(1).stream()
    user_doc = None
    for doc in user_ref:
        # Verify password hash in practice
        user_doc = {"uid": doc.id, "username": doc.to_dict().get("username")}
    if not user_doc:
        raise HTTPException(status_code=401, detail="Invalid credentials")
    
    # Generate a fresh session token and bind to user UID
    session_token = secrets.token_urlsafe(32)
    session_id = secrets.token_hex(16)  # server-side session ID
    session_ref = db.collection("sessions").document(session_id)
    session_ref.set({
        "uid": user_doc["uid"],
        "token": session_token,
        "created_at": datetime.datetime.utcnow(),
        "expires_at": datetime.datetime.utcnow() + datetime.timedelta(hours=1),
        "user_agent": request.headers.get("user-agent", ""),
        "ip_prefix": request.client.host.split(".")[:3]  # example binding
    })
    
    # Set cookie only after session document is confirmed
    response.set_cookie("session_token", session_token, httponly=True, secure=True, samesite="lax")
    return {"session_id": session_id}

Key remediation steps specific to Fastapi and Firestore:

  • Generate a new session ID on login; do not reuse an ID supplied by the client.
  • Store session metadata in Firestore that binds the session to user context (UID, IP prefix, user-agent hash) and enforce these checks on each request.
  • Use Firestore document IDs that are server-generated (e.g., secrets.token_hex) rather than exposing predictable IDs to the client.
  • Validate session existence and ownership on every request by querying Firestore; avoid trusting cookies or headers alone for authorization.
  • Set short expiration times and provide a server-side revocation path by deleting the Firestore session document.

For continuous assurance, the Pro plan’s GitHub Action can be configured to fail builds if session fixation risks are detected during scans, and the dashboard can track session-related findings over time.

Frequently Asked Questions

How does middleBrick detect session fixation risks in Fastapi applications using Firestore?
MiddleBrick checks whether session identifiers are client-controlled and whether they are rotated after authentication. It validates that Firestore document permissions enforce ownership on session reads/writes and that session binding includes user-specific attributes such as UID and contextual metadata.
Can Firestore security rules alone prevent session fixation in Fastapi?
Security rules can restrict who may create or update session documents, but they must be designed to enforce ownership checks on every operation and not rely on client-supplied identifiers for user mapping. Server-side session regeneration and binding are still required to fully mitigate fixation.