Understanding Cookies
Cookies are small text files stored by the browser on behalf of a website. They are the primary mechanism for maintaining state in the stateless HTTP protocol. Every time you stay logged in after closing your browser, a cookie is responsible.
Cookie Attributes
| Attribute | Purpose | Security Impact |
|---|---|---|
| Name=Value | The actual data stored | Should not contain sensitive data in plain text |
| Domain | Which domain can access the cookie | A cookie set for .example.com is accessible by sub.example.com |
| Path | Which URL path can access the cookie | /admin cookie is not sent for /public requests |
| Expires/Max-Age | When the cookie expires | Session cookies expire when the browser closes |
| Secure | Only sent over HTTPS | Prevents transmission over unencrypted connections |
| HttpOnly | Not accessible via JavaScript | Protects against XSS cookie theft |
| SameSite | Controls cross-site sending | Strict, Lax, or None — prevents CSRF attacks |
Testing Cookie Attributes
Open DevTools > Application > Cookies and inspect each cookie:
- Authentication cookies must have Secure, HttpOnly, and SameSite flags
- Session cookies should not have a long Expires/Max-Age
- Domain should be as restrictive as possible
- Path should be limited to the relevant section of the application
Types of Cookies
Session cookies: No expiration date. Deleted when the browser closes. Used for temporary authentication.
Persistent cookies: Have an expiration date. Survive browser restarts. Used for “Remember me” and user preferences.
Third-party cookies: Set by domains other than the one you are visiting. Used for tracking and advertising. Increasingly blocked by browsers.
Client-Side Storage Mechanisms
Modern web applications have multiple ways to store data in the browser.
localStorage
- Stores key-value pairs as strings
- Persists until explicitly cleared by the application or user
- Approximately 5-10 MB per origin
- Accessible by any JavaScript on the same origin
- NOT protected from XSS attacks
sessionStorage
- Same API as localStorage
- Scoped to the browser tab — not shared between tabs
- Cleared when the tab closes
- Useful for temporary data that should not persist
IndexedDB
- Full database in the browser
- Stores structured data, files, and blobs
- Much larger storage capacity (hundreds of MB)
- Asynchronous API — does not block the main thread
- Used by PWAs for offline data storage
Testing Storage Mechanisms
For each storage mechanism, verify:
- Data is stored correctly after user actions
- Data is retrieved correctly on page load
- The application handles missing or corrupted data gracefully
- Storage limits are handled (what happens when localStorage is full?)
- Clearing browser data removes the expected items
- Private/incognito mode behavior is correct
Session Lifecycle
A session has a clear lifecycle that must be tested at every stage:
Login → Session Created → Active Use → Idle Timeout Warning →
Session Expired → Re-authentication → Session Restored/New Session
Testing Session Lifecycle
- Creation: After login, verify a session cookie exists with correct attributes
- Maintenance: Session should renew on activity (sliding expiration)
- Idle warning: Before expiration, show a warning with option to extend
- Expiration: After timeout, redirect to login
- Re-authentication: After re-login, restore context or start fresh
- Destruction: After logout, session is invalidated server-side
Advanced Cookie and Session Testing
Cross-Domain Cookie Testing
When an application spans multiple subdomains (app.example.com, api.example.com):
- Are cookies shared correctly between subdomains?
- Can a subdomain’s cookie interfere with another subdomain?
- Are SameSite restrictions working correctly for cross-origin API calls?
Cookie Size Limits
Browsers limit cookies to approximately 4 KB per cookie and 20-50 cookies per domain:
- What happens when the cookie size limit is reached?
- Does adding a new cookie silently fail or throw an error?
- Are old cookies evicted when the domain limit is reached?
Storage Quota Testing
localStorage has a limit (typically 5-10 MB):
- Fill localStorage to capacity using DevTools Console
- Try to add more data — does the application handle the QuotaExceededError?
- Does the application show a meaningful message or degrade gracefully?
Exercise: Storage Security Audit
Inspect a web application’s storage:
- DevTools > Application > Cookies: List all cookies, check security flags
- DevTools > Application > Local Storage: Check for sensitive data (tokens, PII)
- DevTools > Application > Session Storage: Verify appropriate data scoping
- Manually delete storage items and verify the application recovers gracefully
- Switch to incognito mode — does the application work without stored data?
Document your findings:
| Storage | Key | Contains | Security Issue? |
|---|---|---|---|
| Cookie | session_id | Session token | Missing HttpOnly flag |
| localStorage | auth_token | JWT token | Should be in HttpOnly cookie |
| localStorage | user_email | PII | Consider if necessary |
Session Fixation Prevention
Test that the session ID changes after authentication:
- Note the session cookie value before login
- Log in with valid credentials
- Check the session cookie value — it must be different
- If the same session ID persists, this is a session fixation vulnerability
Key Takeaways
- Cookies are the primary state mechanism — always audit security flags
- HttpOnly prevents XSS theft; Secure prevents cleartext transmission; SameSite prevents CSRF
- localStorage is convenient but vulnerable to XSS — never store auth tokens there
- Test the complete session lifecycle: creation, maintenance, warning, expiration, destruction
- Verify storage limits and quota handling in your application
- Session IDs must change after login to prevent fixation attacks