TT Lab
Get started
Learn Learning paths Courses

Sessions and Tokens — From the Browser to the Mesh

Redis sessions and session fixation defense

Continue in TT Lab

Goal

Stand up a login server with Redis attached as the session store, and confirm with real HTTP requests that the session ID is regenerated at the moment of login, that absolute expiry works regardless of idle, and that logout invalidates immediately.

Why it matters

A server session holds the state on the server and gives the browser only a key. So you can invalidate it immediately with a single logout, but if that key does not change before and after login, session fixation becomes possible, in which someone rides onto my login using a key they planted in advance. OWASP insists on regenerating the session ID at the moment the privilege level changes from anonymous to authenticated. Also, expiry needs both idle (expires with no activity, renewed on every request) and absolute (expires unconditionally once it is old enough), and since Redis TTL alone cannot express absolute, you put the creation time separately inside the value. This lab makes you prove for yourself that these rules hold in real requests.

Steps

  1. Bring up /root/st/session/app.py at 127.0.0.1:8302. GET /health returns 200 and {"ok":true}.
  2. Save, as a single Set-Cookie header line in /root/st/session/cookie.txt, whether the session cookie has the name __Host-sid with Secure, HttpOnly, SameSite, and Path=/.
  3. Get an anonymous session and write into /root/st/session/store.txt whether that ID exists in Redis under the key sess:<id> and has a TTL and a user.
  4. If you log in carrying the anonymous session ID as it is, write into /root/st/session/fixation.txt whether the response gives a different session ID and the old ID disappears.
  5. Write into /root/st/session/idle_ttl.txt whether the login session's TTL is at or below the idle limit and fills back up with a request.
  6. Write into /root/st/session/absolute.txt whether a session with created set to the past is not accepted as authenticated even when idle TTL remains.
  7. Write into /root/st/session/logout.txt whether, after logout, the same cookie falls to anonymous and the store key disappears.
  8. Test the whole flow with /root/st/session/e2e.sh and leave four lines in /root/st/session/e2e.out.

Notes

Bring up the Redis session server

Bring up /root/st/session/app.py at 127.0.0.1:8302. GET /health returns 200 and {"ok":true}.

Redis is already running on 6379. Start the server in the background and poll until it is ready.

Check the session cookie attributes

Save, as a single Set-Cookie header line in /root/st/session/cookie.txt, whether the session cookie has the name __Host-sid with Secure, HttpOnly, SameSite, and Path=/.

The __Host- prefix requires Secure and Path=/ and forbids attaching Domain. Look at the response headers with curl -D - .

That the session is stored in Redis

Get an anonymous session and write into /root/st/session/store.txt, as sid= redis_key= exists=1 ttl=<양수> user=(anon) (the placeholder is a positive number), whether that ID exists in Redis under the key sess:<id> and has a TTL and a user.

Capture the session ID with the cookie jar (-c) and check it with redis-cli EXISTS/TTL/GET.

Regenerate the session ID at login

If you log in carrying the anonymous session ID as it is, write into /root/st/session/fixation.txt, as before= after= changed=yes old_gone=yes, whether the response gives a different session ID and the old ID disappears from the store.

This is the heart of the session fixation defense. On a successful login you must delete the old session and issue a new ID for changed=yes to come out.

Idle timeout is a sliding TTL

Write into /root/st/session/idle_ttl.txt, as ttl_before= ttl_after_request=, whether the login session's Redis TTL is at or below the idle limit and fills back up when you send one more request. Both must be positive, and after must be near the limit.

If you push the TTL out again with EXPIRE on every request, it becomes a sliding idle.

Absolute expiry is independent of TTL

Write into /root/st/session/absolute.txt, as code=200 auth=False gone=yes, whether a session with created set further in the past than the absolute limit and with plenty of idle TTL left is not accepted as authenticated at GET /whoami.

In load_session, if now - created > ABSOLUTE_SEC, you must reject it even when idle TTL remains.

Invalidate immediately at logout

After logging in, log out and then do GET /whoami with the same cookie, and write into /root/st/session/logout.txt, as revoked_auth=False key_gone=yes, whether it falls to anonymous and the store key disappears.

Because the server holds the state, deleting one key invalidates it immediately — this is the difference from a JWT.

Prove the whole flow at once

With /root/st/session/e2e.sh, test in order anonymous, then login regeneration, then authentication, then logout invalidation, and leave reissue=yes, old_gone=yes, logged_in=True, and after_logout=False in /root/st/session/e2e.out.

Chain the earlier steps together in one script. All four lines must come out.