Skip to main content

Overview

The csrf2 middleware provides enhanced CSRF protection using the double submit cookie pattern, where a token is stored in both a cookie and must be submitted in a header or form field. Use it when you need:
  • Stateless CSRF protection
  • Cookie-based token validation
  • Enhanced security for SPAs

Installation

import "github.com/go-mizu/mizu/middlewares/csrf2"

Quick Start

app := mizu.New()

app.Use(csrf2.New(csrf2.Options{}))

app.Post("/submit", func(c *mizu.Ctx) error {
    return c.JSON(200, map[string]string{"status": "ok"})
})

Configuration

Options

OptionTypeDefaultDescription
CookieNamestring"csrf_token"Cookie name
HeaderNamestring"X-CSRF-Token"Header name
FormFieldstring"csrf_token"Form field name
CookiePathstring"/"Cookie path
CookieSecureboolfalseHTTPS only
CookieSameSitehttp.SameSiteLaxSameSite policy
IgnoreMethods[]string["GET", "HEAD", "OPTIONS"]Methods to skip
ErrorHandlerfunc(*mizu.Ctx) error-Custom error handler

Examples

Basic Usage

app.Use(csrf2.New(csrf2.Options{}))

Secure Configuration

app.Use(csrf2.New(csrf2.Options{
    CookieName:     "_csrf",
    HeaderName:     "X-CSRF-Token",
    CookieSecure:   true,
    CookieSameSite: http.SameSiteStrictMode,
}))

Custom Error Handler

app.Use(csrf2.New(csrf2.Options{
    ErrorHandler: func(c *mizu.Ctx) error {
        return c.JSON(403, map[string]string{
            "error": "Invalid CSRF token",
        })
    },
}))

Get Token for Forms

app.Get("/form", func(c *mizu.Ctx) error {
    token := csrf2.Token(c)
    return c.HTML(200, `
        <form method="POST" action="/submit">
            <input type="hidden" name="csrf_token" value="`+token+`">
            <button type="submit">Submit</button>
        </form>
    `)
})

How It Works

  1. Middleware sets CSRF token in cookie
  2. Client reads cookie and includes token in header/form
  3. On state-changing requests, token is validated
  4. If tokens match, request proceeds
  5. If not, returns 403 Forbidden

API Reference

Functions

// New creates CSRF2 middleware
func New(opts Options) mizu.Middleware

// Token returns CSRF token from context
func Token(c *mizu.Ctx) string

Client Implementation

JavaScript (SPA)

// Read token from cookie
function getCsrfToken() {
    return document.cookie
        .split('; ')
        .find(row => row.startsWith('csrf_token='))
        ?.split('=')[1];
}

// Include in requests
fetch('/api/submit', {
    method: 'POST',
    headers: {
        'X-CSRF-Token': getCsrfToken(),
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
});

Technical Details

Token Generation

The middleware generates cryptographically secure tokens using the following process:
  1. Random Bytes: Generates random bytes using crypto/rand
  2. Timestamp: Appends current Unix timestamp for rotation support
  3. Signature: Signs the token with SHA-256 using the provided secret
  4. Encoding: Base64 URL-safe encoding for transport

Token Validation

Token validation uses constant-time comparison to prevent timing attacks:
  1. Decode: Both cookie and submitted tokens are base64-decoded
  2. Length Check: Validates minimum token length (8 bytes)
  3. Constant-Time Compare: Uses XOR-based comparison across all bytes
  4. Result: Returns validation result without early exit
Tokens are stored in HTTP cookies with configurable security options:
  • HttpOnly: Default true to prevent JavaScript access
  • Secure: Configurable for HTTPS enforcement
  • SameSite: Default Lax mode for CSRF protection
  • MaxAge: Default 24 hours (86400 seconds)
  • Path: Default ”/” for site-wide availability

Token Retrieval

The middleware checks for tokens in the following order:
  1. Header: Checks configured header name (default: X-CSRF-Token)
  2. Form: Parses form data for configured field name (default: _csrf)
  3. Query: Checks URL query parameters as fallback

Origin Validation

When enabled, the middleware validates request origin:
  1. Origin Header: Primary validation source
  2. Referer Fallback: Used if Origin header is missing
  3. Allowed Origins: Compares against configured whitelist
  4. Host Match: Falls back to request host if no whitelist specified

Advanced Features

  • Token Masking: XOR-based masking for additional security
  • Fingerprinting: SHA-256 hash of User-Agent and Accept headers
  • Form Input: HTML helper for hidden form fields
  • Meta Tag: HTML meta tag helper for SPAs

Best Practices

  • Always use HTTPS in production
  • Use SameSite Strict for sensitive applications
  • Include token in all state-changing requests
  • Regenerate tokens on authentication changes

Testing

Test Coverage

Test CaseDescriptionExpected Behavior
TestNewBasic middleware initializationCreates middleware and sets CSRF cookie on GET request
TestGetTokenToken retrieval from contextToken is stored in context and retrievable via GetToken()
TestValidateTokenHeaderToken validation via headerPOST request with valid token in header succeeds (200 OK)
TestValidateTokenFormToken validation via form fieldPOST request with valid token in form field succeeds (200 OK)
TestMissingTokenRequest without CSRF tokenPOST request without token returns 403 Forbidden
TestInvalidTokenRequest with invalid tokenPOST request with invalid token returns 403 Forbidden
TestSkipPathsPath exclusion from validationConfigured paths skip CSRF validation
TestSkipMethodsHTTP method exclusionSafe methods (GET, HEAD, OPTIONS) skip validation
TestCustomErrorHandlerCustom error handlingCustom error handler returns JSON response on failure
TestCustomCookieNameCustom cookie configurationCSRF cookie uses configured custom name
TestCustomHeaderNameCustom header configurationToken validation accepts configured custom header name
TestTokenHandlerToken endpoint handlerToken handler returns JSON with current CSRF token
TestFormInputHTML form input helperGenerates hidden input field with token value
TestMetaTagHTML meta tag helperGenerates meta tag with csrf-token name and value
TestMaskUnmaskToken masking/unmaskingMasked token differs from original, unmask restores original
TestFingerprintRequest fingerprintingSame headers produce same fingerprint, different headers differ
  • csrf - Basic CSRF protection
  • session - Session management
  • secure - Security settings