PlugCrossOriginProtection (PlugCrossOriginProtection v0.2.0)
View SourcePlug 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
- Safe methods (GET, HEAD, OPTIONS) are always allowed
- If
Originheader matches a trusted origin, the request is allowed - If
Sec-Fetch-Siteheader issame-originornone, the request is allowed - If
Sec-Fetch-Siteindicates cross-origin, the request is rejected - If no
Sec-Fetch-SiteorOriginheaders are present, the request is allowed (non-browser requests like curl or API clients) - If only
Originis present, it's compared against theHostheader
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:exceptionor:forbidden. Defaults to:exception.:exception- raisesPlugCrossOriginProtection.InvalidCrossOriginRequestError:forbidden- returns a 403 Forbidden response
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: :exceptionSecurity Considerations
- Ensure state-changing actions are never performed on GET requests
- Use HTTPS - the
Sec-Fetch-Siteheader is only sent to secure origins - Consider using HSTS to protect against HTTP->HTTPS attacks on older browsers
Sec-Fetch-Siteis supported in all major browsers since 2023
References
- Cross-Site Request Forgery - Filippo Valsorda's blog post
- Go net/http CrossOriginProtection
- Sec-Fetch-Site MDN