CSRF Attacks
CSRF Attacks
How CSRF Works
- User logs into bank.com, receives session cookie
- User visits malicious site
- Malicious site sends request to bank.com
- Browser automatically includes session cookie
- Bank processes request as if it's from the user
Example Attack
<!-- Malicious site -->
<form action="https://bank.com/transfer" method="POST">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="10000">
</form>
<script>document.forms[0].submit();</script>
Vulnerable Code
// Vulnerable: No CSRF protection
app.post('/transfer', (req, res) => {
// Processes transfer without verifying origin
const { to, amount } = req.body;
transferMoney(req.user, to, amount);
res.json({ success: true });
});
CSRF Targets
- State-changing operations (POST, PUT, DELETE)
- Authentication endpoints
- Financial transactions
- User settings changes
Safe Methods
- GET should be safe (no side effects)
- HEAD, OPTIONS are typically safe
- POST, PUT, DELETE need CSRF protection
CSRF Protection
CSRF Protection
CSRF Tokens
// Server: Generate token
csrfProtection = require('csurf');
app.use(csrfProtection({ cookie: true }));
app.get('/form', (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
app.post('/process', (req, res) => {
// Token is validated automatically
processForm(req.body);
});
Frontend Token Usage
// React: Include token in forms
function TransferForm() {
const [token, setToken] = useState('');
useEffect(() => {
fetch('/api/csrf-token')
.then(res => res.json())
.then(data => setToken(data.token));
}, []);
return (
<form method="POST" action="/transfer">
<input type="hidden" name="_csrf" value={token} />
<input name="to" />
<input name="amount" type="number" />
<button type="submit">Transfer</button>
</form>
);
}
SameSite Cookies
// Set SameSite cookie
res.cookie('session', token, {
httpOnly: true,
secure: true,
sameSite: 'strict', // or 'lax'
});
// SameSite values:
// strict: Cookie only sent for same-site requests
// lax: Cookie sent for top-level navigation (safe default)
// none: Cookie sent for all requests (requires secure)
Origin/Referer Headers
// Server: Verify origin
app.post('/transfer', (req, res) => {
const origin = req.headers.origin || req.headers.referer;
if (!origin || !origin.startsWith('https://myapp.com')) {
return res.status(403).json({ error: 'Invalid origin' });
}
// Process request
});
Double Submit Cookie
// Server: Set random token in cookie and require it in header
const csrfToken = crypto.randomBytes(32).toString('hex');
res.cookie('csrf-token', csrfToken, { sameSite: 'strict' });
// Client: Send token in header
fetch('/api/transfer', {
method: 'POST',
headers: {
'X-CSRF-Token': getCookie('csrf-token'),
},
body: JSON.stringify(data),
});
Additional Protections
Additional Protections
CORS Configuration
// Server: Configure CORS
const cors = require('cors');
app.use(cors({
origin: 'https://myapp.com',
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'X-CSRF-Token'],
}));
Custom Headers
// Client: Always send custom header for AJAX
fetch('/api/transfer', {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
// Server: Verify custom header
app.post('/api/transfer', (req, res) => {
if (req.headers['x-requested-with'] !== 'XMLHttpRequest') {
return res.status(403).json({ error: 'Invalid request' });
}
});
Content-Type Validation
// Server: Only accept specific content types
app.post('/api/transfer', (req, res) => {
if (req.headers['content-type'] !== 'application/json') {
return res.status(415).json({ error: 'Unsupported content type' });
}
});
Frame Protection
// Prevent framing (clickjacking)
app.use((req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
next();
});
Best Practices
- Use SameSite cookies (strict or lax)
- Implement CSRF tokens for state-changing operations
- Validate Origin/Referer headers
- Use custom headers for AJAX requests
- Don't rely solely on CORS for CSRF protection
- Set Content-Type for API requests
- Use HTTPS everywhere
Testing CSRF Protection
describe('CSRF Protection', () => {
it('should reject requests without CSRF token', async () => {
const response = await request(app)
.post('/transfer')
.send({ to: 'attacker', amount: 1000 });
expect(response.status).toBe(403);
});
it('should accept requests with valid CSRF token', async () => {
const token = await getCsrfToken();
const response = await request(app)
.post('/transfer')
.set('X-CSRF-Token', token)
.send({ to: 'friend', amount: 100 });
expect(response.status).toBe(200);
});
});
Practice Problems
Create a reusable React component implementing Cross-Site Request Forgery (CSRF). Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for Cross-Site Request Forgery (CSRF) using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize Cross-Site Request Forgery (CSRF) for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What is CSRF?
2. What is SameSite cookie attribute?
3. What is the primary purpose of Cross-Site Request Forgery (CSRF)?
4. What is a common mistake when implementing Cross-Site Request Forgery (CSRF)?
Flashcards
Question
What is CSRF?
Click to reveal answer
Answer
Cross-Site Request Forgery - tricking users into making unintended state-changing requests.
Question
What is SameSite cookie?
Click to reveal answer
Answer
An attribute that controls when cookies are sent with cross-site requests.
Question
How do CSRF tokens work?
Click to reveal answer
Answer
A random token is generated server-side and must be included in requests to verify origin.
Question
Which requests need CSRF protection?
Click to reveal answer
Answer
State-changing requests: POST, PUT, DELETE (not GET which should be safe).
Question
What is Cross-Site Request Forgery (CSRF)?
Click to reveal answer
Answer
Cross-Site Request Forgery (CSRF) is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.CSRF tricks users into making unintended requests
- 2.Use SameSite cookies as primary defense
- 3.CSRF tokens protect state-changing operations
- 4.GET requests should be safe (no side effects)
- 5.Validate Origin/Referer headers
Interview Tips
- •Explain how CSRF attacks work
- •Discuss SameSite cookie attribute
- •Know multiple CSRF protection methods
Cheat Sheet
CSRF Protection Cheat Sheet
Attack
- User visits malicious site
- Malicious site sends request to your app
- Browser includes session cookie
- App processes as legitimate request
Protection Methods
- CSRF Tokens
- SameSite cookies
- Origin/Referer validation
- Custom headers
- CORS configuration
SameSite Values
- strict: Only same-site
- lax: Top-level navigation
- none: All requests (needs secure)
Best Practices
- Use SameSite: strict or lax
- CSRF tokens for state changes
- Validate Origin header
- Use custom headers for AJAX