CSRF Protection

Protection against Cross-Site Request Forgery attacks using the double-submit cookie pattern.

What is CSRF?

Cross-Site Request Forgery (CSRF) is an attack that tricks users into performing unwanted actions on a site where they're authenticated. For example, an attacker could craft a malicious link that transfers money or changes account settings.

How ShipCommerce Protects You

ShipCommerce implements the double-submit cookie pattern:

  1. A cryptographically random CSRF token is generated
  2. Token is stored in an HttpOnly cookie
  3. Token is also included in form submissions/API requests
  4. Server verifies both values match
  5. Tokens rotate every 24 hours

Implementation

// CSRF token generation
import { randomBytes } from 'crypto';

function generateCsrfToken(): string {
  return randomBytes(32).toString('hex');
}

// Cookie settings (HttpOnly, Secure, SameSite)
const csrfCookieOptions = {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict' as const,
  maxAge: 60 * 60 * 24, // 24 hours
  path: '/',
};

Using CSRF Protection

In Forms

// Forms automatically include CSRF token
<form action="/api/checkout" method="POST">
  <input type="hidden" name="_csrf" value={csrfToken} />
  {/* form fields */}
</form>

In API Requests

// Include CSRF token in headers
fetch('/api/cart/add', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken,
  },
  body: JSON.stringify({ productId, quantity }),
});

Server-Side Verification

// API route middleware
import { verifyCsrfToken } from '@/lib/csrf';

export async function POST(request: Request) {
  // Verify CSRF token
  const isValid = await verifyCsrfToken(request);

  if (!isValid) {
    return Response.json(
      { error: 'Invalid CSRF token' },
      { status: 403 }
    );
  }

  // Process the request...
}

Security Features

  • HttpOnly cookie — Token cannot be accessed by JavaScript
  • Secure flag — Only sent over HTTPS in production
  • SameSite=Strict — Cookie not sent with cross-site requests
  • 24-hour rotation — Tokens expire and regenerate
  • Cryptographically random — Unpredictable tokens

Exempt Routes

Some routes are exempt from CSRF protection by design:

  • Stripe webhooks — Verified by Stripe signature instead
  • Public API endpoints — Read-only operations
  • Authentication — Uses separate token mechanism

Note: CSRF protection is automatically enabled for all state-changing operations. You don't need to configure anything.