Sessions, Cookies, and CSRF
Check that logout kills the session, cookies are flagged, and a cross-site POST cannot ride the user's cookie.
This post is part of the Security Testing Basics series. If you missed the previous post, read Part 3 — Access Control Cases a Scanner Will Miss first.
Introduction — Login Was Tested. Leaving Was Not.
The suite signs in at the start and never signs out. The session cookie lives as long as the browser profile. A form on another site can post to yours, and the browser will attach the cookie if you let it.
Three checks. None of them require a new tool.
Logout Kills the Server Session
Sign in. Copy the session cookie. Sign out. Send a request with the copied cookie.
curl -s -o /dev/null -w "%{http_code}" \
-H "Cookie: session=$OLD" \
https://staging.example.com/api/me
You want 401. If you still get the user’s profile, logout only cleared the browser. Anyone who copied the cookie is still in.
Do the same after a password change. Old sessions should die. If the product promises “sign out of all devices,” that is two sessions, not one browser.
The Cookie Flags
In DevTools, or in the Set-Cookie header, the session cookie needs:
- Secure — it will not travel over plain HTTP
- HttpOnly — page script cannot read it
- SameSite —
LaxorStrict, so a foreign site’s POST does not bring it along - a bounded lifetime, not a cookie that expires in 2035
A missing HttpOnly means a script injection becomes a stolen session. That is why part 1 treats XSS as more than a popup.
A Foreign Page Must Not Change State
Host a tiny HTML file that posts to your staging origin:
<form action="https://staging.example.com/api/email" method="POST">
<input name="email" value="attacker@example.com" />
</form>
<script>document.forms[0].submit()</script>
Open it while you are logged in to staging. The email on the account must not change.
SameSite=Lax blocks most of these cross-site POSTs in current browsers. It is not a reason to skip the test. A cookie set to SameSite=None so that a widget on another site can call you is exactly the cookie this form will ride. Those endpoints need a second check the foreign page does not have: a CSRF token, or a header the form cannot set, checked on the server.
A test that only looks at your own origin’s form will never see this. The hostile page is the test.
Conclusion
Logout must invalidate the session you copied. The cookie must not be readable by script or attachable by a foreign form. Prove the foreign form against staging, not against your own UI.
Action for this week: Copy the session cookie, log out, and call /api/me with it. Then read Set-Cookie and write down any missing flag.
Next in the series: Part 5 — Security Checks That Belong in CI.