A Plug to protect against Cross-Site Request Forgery (CSRF) attacks using modern header-based checks instead of tokens.
Based on Filippo Valsorda's blog post and the
Go 1.25 net/http CrossOriginProtection.
Modern browsers (since 2023) send the Sec-Fetch-Site header which reliably
indicates whether a request is same-origin, same-site, cross-site, or
user-initiated. This plug uses that header (with a fallback to Origin header
comparison) to reject cross-origin requests without requiring CSRF tokens.
- Safe methods (GET, HEAD, OPTIONS) are always allowed
- If
Originheader matches a trusted origin, the request is allowed - If
Sec-Fetch-Siteissame-originornone, the request is allowed - If
Sec-Fetch-Siteindicates cross-origin, the request is rejected - If no headers are present, the request is allowed (non-browser client)
- If only
Originis present, it's compared against theHostheader
Add plug_cross_origin_protection to your list of dependencies in mix.exs:
def deps do
[
{:plug_cross_origin_protection, "~> 0.2"}
]
endIf you're using Phoenix, PlugCrossOriginProtection is a direct replacement for
the protect_from_forgery helper which invokes
Plug.CSRFProtection.
# In your YourAppWeb.Router
- plug :protect_from_forgery
+ plug PlugCrossOriginProtectionFor SSO callbacks or partner integrations:
plug PlugCrossOriginProtection,
trusted_origins: [
"https://sso.example.com",
"https://partner.example.com"
]- Safe methods: Ensure your application never performs state-changing actions on GET, HEAD, or OPTIONS requests
- HTTPS: Use HTTPS in production. The
Sec-Fetch-Siteheader is only sent to secure origins - HSTS: Consider using HTTP Strict Transport Security to protect against HTTP→HTTPS attacks on older browsers
- Browser support:
Sec-Fetch-Siteis supported in all major browsers since 2023. Older browsers fall back to Origin/Host comparison
MIT License. See LICENSE for details.