This shop keeps sessions on the server: SESSIONS maps a random id to the visitor's data, and the id travels in the sid cookie. load_session gives every new visitor a session, so guests can fill a cart, and save_session puts g.sid into the cookie after each request.
The hole: at login, the starting code writes the email into the session the browser already has, and an attacker can choose that session. They open the shop on a library computer, copy its sid cookie and walk away. When Ana logs in on that computer, the attacker's own browser, sending the same id, is logged in as Ana: it sees her account and can order with it. This is session fixation.
The fix: give the visitor a new session id at login. Delete the old session, make a new random id and store the email under it; the id the attacker copied then names nothing. Do it again at logout, so the next person at the computer starts clean. Here is the same move for a shop worker who unlocks the admin pages, keeping the session's data but not its id:
@app.post("/admin/unlock")
def unlock():
# ...after checking the admin password...
data = SESSIONS.pop(g.sid)
g.sid = secrets.token_urlsafe(16)
SESSIONS[g.sid] = data
SESSIONS[g.sid]["admin"] = True
return jsonify({"message": "Admin pages unlocked"})
The check runs two browsers, each with its own cookies. Before the login it copies the attacker's cookie into the victim's browser, just like the library computer:
POST /cart {"product_id": 3} (attacker) → 200 {"cart": [3]}
POST /login {"email": "ana@example.com", "password": "ana-pass-123"} (victim, with the attacker's cookie) → 200 {"message": "Logged in"}
GET /me (victim) → 200 {"email": "ana@example.com"}
GET /me (attacker) → 401 {"error": "Login required"}
POST /cart {"product_id": 1} (victim) → 200 {"cart": [1]}
POST /logout (victim) → 200 {"message": "Logged out"}
POST /cart {"product_id": 4} (victim) → 200 {"cart": [4]}
GET /me (victim) → 401 {"error": "Login required"}
Your task: write fresh_session(): it deletes the current session, sets g.sid to a new id from secrets.token_urlsafe(16) and stores an empty session, {"cart": []}, under it. Then call it in login, before the email is stored, and in logout, after the email is removed.
Assignment
Follow the Coding Tutorial to give the visitor a new session id at login, and again at logout.
Hint
Delete the old session while g.sid still holds the old id, then change g.sid. You don't touch the cookie yourself: save_session sends whatever g.sid holds.
Free plan: 30 tutor messages. PRO is unlimited.
