CSRF Protection (Cross-Site Request Forgery)
Overview
CSRF protection prevents attackers from tricking authenticated users into performing unwanted actions by validating that requests originate from your application.
Why This Is Important
The Problem: Cross-Site Request Forgery
Attackers trick authenticated users' browsers into making malicious requests:
1. State-Changing Actions
<!-- Attacker's malicious website -->
<img src="https://yourbank.com/transfer?to=attacker&amount=10000">
<!-- When logged-in user visits attacker's site: -->
<!-- Browser automatically sends cookies with request -->
<!-- Bank processes transfer without user knowledge -->
What Happens Without Protection:
- Browser sends authentication cookies
- Server sees valid session
- Action executed without consent
Impact:
- Unauthorized transfers
- Data deletion
- Settings changed
- Account takeover
2. Form Auto-Submission
<!-- Attacker's page -->
<form action="https://yoursite.com/api/user/delete" method="POST">
<input type="hidden" name="confirm" value="yes">
</form>
<script>
document.forms[0].submit();
</script>
What Happens Without Protection:
- Form auto-submits on page load
- User's cookies sent automatically
- Account deleted without consent
Impact: Account deleti Data lo Security settings chang Privacy violations
3. JSON API Exploitation
// Attacker's website makes fetch request
fetch('https://yoursite.com/api/admin/promote', {
method: 'POST',
credentials: 'include', // Sends cookies
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userId: 'attacker', role: 'admin' })
});
What Happens Without Protection:
- Credentials included automatically
- Admin API called
- Attacker promoted to admin
Impact: Privilege escalation Unauthorized access Admin rights granted Full compromise
4. Silent Background Requests
<!-- Invisible iframe on attacker's site -->
<iframe style="display:none"
src="https://yoursite.com/api/settings?email=attacker@evil.com">
</iframe>
What Happens Without Protection:
- Request made in background
- User doesn't notice
- Email changed to attacker's
Impact:
- Email hijacking
- Password reset to attacker
- Account takeover
- Complete compromise
How nextjs-fortress Solves This
Token Generation
/**
* Generate a new CSRF token for a session
*/
public async generateToken(sessionId: string): Promise<string> {
const tokenLength = this.config.tokenLength || 32;
const expiryMs = this.config.expiryMs || 24 * 60 * 60 * 1000;
// Generate random token
const randomBuffer = await generateRandomBytes(tokenLength);
const randomToken = arrayBufferToHex(randomBuffer.buffer);
// Create HMAC signature
const signature = await this.createSignature(randomToken, sessionId);
const token = `${randomToken}.${signature}`;
// Store token with expiry
tokenStore.set(sessionId, {
token,
createdAt: Date.now(),
expiresAt: Date.now() + expiryMs,
});
return token;
}
Token Validation
/**
* Validate CSRF token from request
*/
public async validate(
token: string | null | undefined,
sessionId: string,
method: string
): Promise<ValidationResult> {
// Safe methods don't require CSRF protection
const safeMethods = ['GET', 'HEAD', 'OPTIONS'];
if (safeMethods.includes(method.toUpperCase())) {
return { valid: true };
}
// No token provided
if (!token) {
return {
valid: false,
severity: 'high',
message: 'CSRF token missing',
rule: 'csrf_token_missing',
confidence: 1.0,
};
}
// Get stored token
const storedToken = tokenStore.get(sessionId);
if (!storedToken) {
return {
valid: false,
severity: 'high',
message: 'No CSRF token found for session',
rule: 'csrf_no_session_token',
confidence: 1.0,
};
}
// Check expiry
if (Date.now() > storedToken.expiresAt) {
tokenStore.delete(sessionId);
return {
valid: false,
severity: 'medium',
message: 'CSRF token expired',
rule: 'csrf_token_expired',
confidence: 1.0,
};
}
// Validate token matches
if (token !== storedToken.token) {
return {
valid: false,
severity: 'critical',
message: 'Invalid CSRF token',
rule: 'csrf_token_invalid',
confidence: 1.0,
};
}
// Verify signature
const [randomPart, signature] = token.split('.');
const expectedSignature = await this.createSignature(randomPart, sessionId);
if (signature !== expectedSignature) {
return {
valid: false,
severity: 'critical',
message: 'CSRF token signature mismatch',
rule: 'csrf_signature_invalid',
confidence: 1.0,
};
}
return { valid: true };
}
Attack Prevention Examples
Example 1: Form Submission Attack
// Attacker tries to submit form
POST /api/user/delete
Cookie: session=user123
// Missing CSRF token
// Fortress response:
{
"error": "CSRF token missing",
"rule": "csrf_token_missing"
}
// Status: 403 Forbidden
// Result: BLOCKED ✅
Example 2: Invalid Token Attack
// Attacker uses fake token
POST /api/admin/promote
Cookie: session=user123
X-CSRF-Token: fake-token-12345
// Fortress validates:
// 1. Token format check
// 2. Signature verification
// 3. Session matching
// Result: BLOCKED ✅
Example 3: Expired Token
// Token expired after 24 hours
POST /api/settings
Cookie: session=user123
X-CSRF-Token: old-token.signature
// Fortress response:
{
"error": "CSRF token expired",
"rule": "csrf_token_expired"
}
// Result: BLOCKED ✅
How to Initialize
import { FortressConfig, FortressLogger } from '@mindfiredigital/nextjs-fortress';
export const fortressConfig: FortressConfig = {
enabled: true,
mode: 'development',
modules: {
csrf: {
enabled: true,
cookieName: '_csrf',
headerName: 'X-CSRF-Token',
tokenSecret: process.env.CSRF_SECRET,
tokenLength: 32,
expiryMs: 24 * 60 * 60 * 1000, // 24 hours
},
},
onSecurityEvent: async (event) => {
if (event.type === 'csrf') {
const logger = new FortressLogger({
enabled: true,
level: 'warn',
destination: 'console',
});
logger.warn('🛡️ CSRF Attack Blocked', {
rule: event.detection.rule,
ip: event.request.ip,
path: event.request.path,
});
}
},
};
Token Lifecycle
- Generation - Token created when user visits site
- Storage - Token stored in cookie and server-side
- Validation - Token checked on state-changing requests
- Expiry - Token expires after configured time
- Cleanup - Expired tokens removed automatically
Summary
What happens without CSRF protection:
- Unauthorized actions
- Account takeover
- Data manipulation
- Silent attacks
What nextjs-fortress provides:
- Cryptographic tokens
- Signature verification
- Automatic validation
- Expiry management
How to initialize:
csrf: {
enabled: true,
cookieName: '_csrf',
tokenSecret: process.env.CSRF_SECRET,
}
Related Documentation: