AI Skill Library

CSRF Protection

Token patterns, SameSite cookies, double submit, framework middleware.

securitybackendfrontend
# CSRF Protection

## What is CSRF?
Attacker tricks user's browser into making requests to your site using the user's session.
```html
<!-- On evil.com -->
<img src="https://bank.com/transfer?to=attacker&amount=10000" />
<form action="https://bank.com/transfer" method="POST" id="f">
  <input name="to" value="attacker" />
  <input name="amount" value="10000" />
</form>
<script>document.getElementById('f').submit()</script>
```

## Defense 1: SameSite cookies (primary)
```ts
res.cookie('session', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'lax',     // blocks cross-site POST
  // sameSite: 'strict' // blocks ALL cross-site requests
  maxAge: 86400000,
})
```
`Lax`: blocks cross-site POST/PUT/DELETE. Allows GET navigation (links).
`Strict`: blocks ALL cross-site requests including navigation.

## Defense 2: CSRF token
```ts
// Server: generate token per session
import crypto from 'node:crypto'
const csrfToken = crypto.randomBytes(32).toString('hex')
req.session.csrfToken = csrfToken

// Send token to client (in HTML or cookie)
<input type="hidden" name="_csrf" value="{csrfToken}" />

// Verify on mutation
if (req.body._csrf !== req.session.csrfToken) {
  return res.status(403).json({ error: 'Invalid CSRF token' })
}
```

## Defense 3: Check Origin header
```ts
function verifyCsrf(req, res, next) {
  if (['POST','PUT','DELETE','PATCH'].includes(req.method)) {
    const origin = req.headers.origin || req.headers.referer
    if (!origin?.startsWith('https://yourdomain.com')) {
      return res.status(403).json({ error: 'CSRF rejected' })
    }
  }
  next()
}
```

## Modern SPAs
- API-only backends using `Authorization: Bearer` header are **immune** to CSRF.
  (Browsers don't auto-attach custom headers cross-origin.)
- If using cookies for auth in SPA: use `SameSite=Lax` + CSRF token.

## Checklist
- [ ] `SameSite=Lax` or `Strict` on all auth cookies.
- [ ] CSRF token for cookie-based sessions.
- [ ] Validate `Origin` header on mutations.
- [ ] Never use GET for state-changing operations.

API: /api/skills/csrf-protection