Double Submit Cookie is a CSRF protection technique that verifies the legitimacy of requests by storing the same Token in both the Cookie and request parameters.
Basic Principles of Double Submit Cookie
- Token Generation: Server generates a random CSRF Token
- Double Storage: Token is stored in both Cookie and request parameters
- Verification Logic: Server verifies whether the Token in Cookie matches the Token in request parameters
Implementation Steps
1. Generate Token
javascriptfunction generateCSRFToken() { return crypto.randomBytes(32).toString('hex'); } // Middleware: Generate and set Token function csrfTokenMiddleware(req, res, next) { const token = generateCSRFToken(); res.cookie('csrfToken', token, { httpOnly: false, // JavaScript needs to read secure: true, sameSite: 'strict' }); res.locals.csrfToken = token; next(); }
2. Include Token in Form
html<form action="/api/submit" method="POST"> <input type="hidden" name="csrfToken" value="<%= csrfToken %>"> <!-- Other form fields --> <button type="submit">Submit</button> </form> <!-- Or set via JavaScript --> <script> const form = document.querySelector('form'); const csrfToken = document.querySelector('meta[name="csrf-token"]').content; const input = document.createElement('input'); input.type = 'hidden'; input.name = 'csrfToken'; input.value = csrfToken; form.appendChild(input); </script>
3. Verify Token
javascriptfunction validateDoubleSubmitCookie(req) { const cookieToken = req.cookies.csrfToken; const paramToken = req.body.csrfToken || req.query.csrfToken; if (!cookieToken || !paramToken) { return false; } // Use constant-time comparison to prevent timing attacks return crypto.timingSafeEqual( Buffer.from(cookieToken), Buffer.from(paramToken) ); } // Verification middleware function csrfProtection(req, res, next) { if (req.method === 'GET' || req.method === 'HEAD' || req.method === 'OPTIONS') { return next(); } if (!validateDoubleSubmitCookie(req)) { return res.status(403).send('CSRF token validation failed'); } next(); }
How It Works
Why Double Submission Works?
- Same-Origin Policy: Malicious websites cannot read target website's cookies
- Cross-site Request Restrictions: Malicious websites cannot include correct Token in request parameters
- Match Verification: Only same-origin requests can access both Cookie and set request parameters
Attack Scenario Analysis
html<!-- Malicious website attempts CSRF attack --> <form action="https://example.com/api/transfer" method="POST"> <input type="hidden" name="to" value="attacker"> <input type="hidden" name="amount" value="1000"> <!-- Cannot obtain correct csrfToken --> </form> <script> document.querySelector('form').submit(); </script>
- Malicious website can initiate request
- Browser automatically sends Token from Cookie
- But malicious website cannot include correct Token in request parameters
- Server verification fails, request rejected
Advantages
- No Server State: No need to store Token on server
- Easy to Implement: Relatively simple implementation
- Scalability: Suitable for distributed systems
- Good Performance: No need to query database or Session
Limitations
-
Cookie Security:
- Protection fails if Cookie is stolen (XSS)
- Need to use with HttpOnly (but JavaScript cannot read)
-
Subdomain Risk:
- If subdomain has XSS vulnerability, may affect main domain
- Need to carefully set Cookie's domain attribute
-
Token Leakage:
- If Token is exposed in URL, may be recorded in logs
- Should use POST request to pass Token
Best Practices
1. Combine with Other Protection Measures
javascriptapp.use(helmet()); // XSS protection app.use(cookieSession({ secret: 'secret', cookie: { httpOnly: true, secure: true, sameSite: 'strict' } })); app.use(csrfTokenMiddleware); app.use(csrfProtection);
2. Token Refresh Strategy
javascript// Refresh Token after each request function refreshTokenMiddleware(req, res, next) { if (req.method !== 'GET' && req.method !== 'HEAD') { const newToken = generateCSRFToken(); res.cookie('csrfToken', newToken, { httpOnly: false, secure: true, sameSite: 'strict' }); res.locals.csrfToken = newToken; } next(); }
3. Security Configuration
javascript// Cookie configuration res.cookie('csrfToken', token, { httpOnly: false, // Allow JavaScript to read secure: true, // HTTPS only sameSite: 'strict', // Strictest same-site policy maxAge: 3600000, // 1 hour expiration domain: '.example.com' // Carefully set domain });
Comparison with CSRF Token
| Feature | Double Submit Cookie | Traditional CSRF Token |
|---|---|---|
| Server State | Not needed | Needs Session |
| Implementation Complexity | Simple | Medium |
| Distributed Support | Excellent | Needs shared Session |
| Security | Good | Excellent |
| Performance | Excellent | Good |
Double Submit Cookie is an effective CSRF protection technique, especially suitable for distributed systems and scenarios requiring high performance. But it should be used with other security measures to provide comprehensive security protection.