Skip to course content
Free generative AI app course

Generative AI Application Development with Python

Unit 07.02: One user's history, and keeping it theirs

Session state keyed on a session id alone is state a guessed id can read.

The user id must come from your authenticated session

Two users with the same session id, kept apart by the key.

The code shows no crossover.

SESSIONS = {}


def history(user_id, session_id):
    """Keyed on BOTH. A session id alone is guessable and reusable."""
    return SESSIONS.setdefault((user_id, session_id), [])


history("user-a", "s-1").append("user A: my account is ACC-1187")
history("user-b", "s-1").append("user B: my account is ACC-9002")

for (user, session), msgs in SESSIONS.items():
    print(f"{user} / {session}: {msgs}")

leaked = "user A: my account is ACC-1187" in history("user-b", "s-1")
print(f"\nuser-b can see user-a's history: {leaked}")
print("the user id must come from your authenticated session, never the request")

# Session ids leak -- into URLs, logs, screenshots and support tickets. Keying
# on the session alone means a leaked id reads someone's conversation,
# including whatever account numbers are in it.

Keyed on the session alone, user B would read user A's conversation - including the account number in it. The pair key makes that structurally impossible.

The important half is where the user id comes from. Taken from the request body it is a suggestion, and an attacker supplies whichever value they like.

The mistake this prevents

The mistake is relying on the session id being hard to guess. Session ids leak - into URLs, server logs, screenshots and support tickets - and unguessability is not an access control.

Takeaway

Key session state on the authenticated user id and the session id together. Never take the user id from the request body.