CS 360 — Cross-Site Scripting, Cross-Site Request Forgery, and how cookies protect you
Set four cookies with different security attributes, then see which ones XSS and CSRF can exploit.
Open Chrome DevTools (F12) and try these in the Console tab:
Notice: httponly_session is missing from the output — HttpOnly cookies are invisible to JavaScript.
But check DevTools → Application → Cookies — it's there, and the browser sends it on every request.
Lists just the cookie names visible to JS.
Inject JavaScript into a vulnerable page and steal cookies visible to JS.
document.cookie. This lets the attacker steal session tokens, modify the page,
or perform actions as the user.
The server has a /api/xss/search?q=... endpoint that reflects user input
without escaping. Type a normal search, then try injecting HTML/JS:
Server response rendered as HTML:
Paste each into the search box and click Search (Vulnerable). Watch the iframe and your console.
1. Basic injection — inject bold HTML:
2. Script injection — pop an alert:
3. Cookie theft — steal document.cookie:
Check the Network tab — the stolen cookies are sent as a query parameter. In a real attack, this would go to the attacker's server.
4. DOM manipulation — deface the page:
Open the Console (F12) and run these directly. Compare what's visible:
httponly_session cookie is
invisible to document.cookie and all JavaScript. Even if XSS executes,
it cannot steal this cookie. That's why session tokens should always be HttpOnly.
A malicious page on port 5051 performs actions on port 5050 using YOUR cookies.
Add a note normally, then see what happens when the attacker page adds one for you.
Click the button below to open the evil attacker page on port 5051. That page will automatically submit a hidden form that POSTs to this server (port 5050). Since your browser has a session cookie for port 5050, it may be sent along automatically.
<form> that auto-submitted a POST to localhost:5050/api/csrf/add-note.
session_token cookie (because the form targets port 5050).
Open console on the evil page (port 5051) and try:
How the SameSite attribute controls whether cookies are sent on cross-site requests.
Secure flag. This is what the old pre-SameSite web looked like — fully vulnerable to CSRF.
Open DevTools → Application → Cookies → http://localhost:5050 and look at the SameSite column for each cookie.
All cookies are sent — because this is a same-site request.
On cross-site fetch: Strict cookies are NOT sent. Lax cookies are NOT sent (it's not a top-level navigation). Only None cookies would be sent.
| Attack vector | SameSite=None | SameSite=Lax | SameSite=Strict |
|---|---|---|---|
| Cross-site form POST | Cookie sent | NOT sent | NOT sent |
| Cross-site link (GET) | Cookie sent | Cookie sent | NOT sent |
| Cross-site fetch/XHR | Cookie sent | NOT sent | NOT sent |
| Iframe / embedded | Cookie sent | NOT sent | NOT sent |
| Same-site (any) | Cookie sent | Cookie sent | Cookie sent |
A server-generated secret that the attacker cannot guess or obtain.
This uses the /api/csrf/add-note-protected endpoint which requires a valid token.
SameSite=Lax cookies (blocks most CSRF)
AND CSRF tokens (catches edge cases like SameSite=None or older browsers).
Two different attacks, two different defense strategies.
| XSS | CSRF | |
|---|---|---|
| What | Inject malicious JS into the page | Trick browser into sending a forged request |
| Attacker sees cookies? | Yes (non-HttpOnly) | No — just tricks browser into using them |
| Runs code on victim page? | Yes | No |
| Primary defense | Output escaping + HttpOnly cookies + CSP | SameSite cookies + CSRF tokens |
| Cookie attribute | HttpOnly prevents JS from reading |
SameSite prevents cross-site sending |