Key Takeaways
- CSRF forces users to perform unwanted actions
- Tokens are the primary defense
- SameSite cookies provide additional protection
- State-changing actions must be protected
Contents
1. What is CSRF?
Cross-Site Request Forgery (CSRF) tricks authenticated users into performing actions they didn't intend. The attacker crafts a malicious request that the victim's browser sends automatically with their session cookies.
2. How CSRF Works
- User logs into bank.com (receives session cookie)
- User visits attacker's malicious site
- Malicious site sends request to bank.com
- Browser includes session cookie automatically
- Bank processes request as legitimate
3. CSRF Attack Examples
GET-based CSRF
<!-- Hidden image triggers GET request -->
<img src="https://bank.com/transfer?to=attacker&amount=1000" />
<!-- Or hidden iframe -->
<iframe src="https://bank.com/transfer?to=attacker&amount=1000" style="display:none"></iframe>
POST-based CSRF
<form action="https://bank.com/transfer" method="POST" id="csrfForm">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="1000">
</form>
<script>document.getElementById('csrfForm').submit();</script>
4. CSRF Token Implementation
Server-side Token Generation
# Generate token (PHP)
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
# Include in form
<input type="hidden" name="csrf_token" value="">
# Validate on submission
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
die('CSRF validation failed');
}
5. SameSite Cookies
# SameSite cookie attribute
Set-Cookie: session=abc123; SameSite=Strict
Set-Cookie: session=abc123; SameSite=Lax
# Strict: Cookie only sent on same-site requests
# Lax: Cookie sent on safe top-level navigations (GET)
# None: Cookie always sent (requires Secure)
# PHP
session_set_cookie_params([
'samesite' => 'Lax',
'secure' => true,
'httponly' => true
]);
6. Testing for CSRF
# Manual testing:
1. Identify state-changing actions
2. Capture legitimate request
3. Craft malicious HTML page
4. Test if action succeeds without token
# Burp Suite:
1. Right-click request
2. Engagement tools → Generate CSRF PoC
3. Test PoC in browser
# Check for:
- Missing CSRF tokens
- Token not validated
- Token reuse across sessions
- Predictable tokens
7. Common Bypass Techniques
- Token removal: Delete token parameter entirely
- Empty token: Submit empty string
- Token from another user: Generate with attacker account
- HTTP method change: POST to GET
- Content-Type change: JSON to form data
8. Complete CSRF Prevention
Defense Checklist
- ✅ Use CSRF tokens for all state-changing requests
- ✅ Validate tokens server-side
- ✅ Use SameSite=Lax or Strict cookies
- ✅ Verify Origin/Referer headers
- ✅ Use framework's built-in CSRF protection
- ✅ Don't use GET for state-changing operations
FAQ
Is SameSite=Lax enough protection?
SameSite=Lax helps but isn't complete. It allows cookies on safe top-level GET navigations. Combined with CSRF tokens and proper HTTP methods, it provides strong defense.