PlugCrossOriginProtection (PlugCrossOriginProtection v0.2.0)

View Source

Plug to protect from cross-site request forgery (CSRF) using header-based checks.

Unlike token-based CSRF protection, this plug uses modern browser headers (Sec-Fetch-Site and Origin) to detect and reject cross-origin requests. This approach requires no session state or token management.

For this plug to be effective, state-changing actions must not be performed on GET, HEAD, or OPTIONS requests, as these are always allowed.

How it works

  1. Safe methods (GET, HEAD, OPTIONS) are always allowed
  2. If Origin header matches a trusted origin, the request is allowed
  3. If Sec-Fetch-Site header is same-origin or none, the request is allowed
  4. If Sec-Fetch-Site indicates cross-origin, the request is rejected
  5. If no Sec-Fetch-Site or Origin headers are present, the request is allowed (non-browser requests like curl or API clients)
  6. If only Origin is present, it's compared against the Host header

Options

  • :trusted_origins - an optional list of trusted origin strings that bypass protection. Origins must be in the format "scheme://host" or "scheme://host:port". Example: ["https://sso.example.com", "https://partner.example.com:8443"]

  • :with - should be one of :exception or :forbidden. Defaults to :exception.

Disabling

You may disable this plug by setting Plug.Conn.put_private(conn, :plug_skip_cross_origin_protection, true).

This is useful for:

  • SSO/OAuth callback endpoints
  • Webhook endpoints that receive cross-origin requests
  • Public API endpoints

Examples

# Basic usage
plug PlugCrossOriginProtection

# With trusted origins
plug PlugCrossOriginProtection,
  trusted_origins: ["https://sso.example.com"]

# Raise exception instead of 403
plug PlugCrossOriginProtection, with: :exception

Security Considerations

  • Ensure state-changing actions are never performed on GET requests
  • Use HTTPS - the Sec-Fetch-Site header is only sent to secure origins
  • Consider using HSTS to protect against HTTP->HTTPS attacks on older browsers
  • Sec-Fetch-Site is supported in all major browsers since 2023

References