engineeringdept

engineeringdept

Proposal to migrate to tokenless/header only CSRF in Plug/Phoenix

In 2026 double submit/session tokens are no longer necessary to prevent against CSRF attacks. Instead, we can use the Sec-Fetch-Site header, with a fallback of the Origin header. This has a couple of advantages:

  1. Removes a whole class of easy-to-make mistakes around CSRF token handling - e.g. accidentally not passing a token through to a JS request
  2. Removes any issues related to long-lived CSRF tokens in non-cookie session storage - e.g. a user returning to the site after their CSRF token has disappeared from the Redis backed session storage and their next actions failing

This blog post does a good job of outlining how to prevent against CSRF attacks using these headers and the issues around legacy browsers. It has been adopted in Go 1.25 in the net/http middleware.

I’ve had a go at implementing a Plug which does same: GitHub - breakroom/plug_cross_origin_protection: A Plug to protect against Cross-Site Request Forgery (CSRF) attacks using modern header-based checks instead of tokens · GitHub (this is not yet in production, but likely will be after more thorough review.)

Is there any interest in adopting this approach in Plug/Phoenix and dropping CSRF tokens ( Plug.CSRFProtection — Plug v1.20.2 ) entirely? Or should I continue with a separate library?

Most Liked

josevalim

josevalim

Creator of Elixir

Ship your thing and collect feedback! That will be useful for upstreaming it later when the time is right!

LostKobrakai

LostKobrakai

I was looking at the readme. I don‘t think the skip example is correct. The plug in the controller would only run after the plug in e.g. the router pipeline. So you‘d store the intent to skip after the skippable plug already executed.

I‘m also curious about the exception. Imo an exception should be the default with a Plug.Exception integration to turn it into a 403 (e.g. have a plug_status field of 403). That‘s how plug itself handles that.

I also see you using the Plug namespace. Before publishing you‘d want to change that to your own namespace: Library Guidelines — Elixir v1.12.3

derek-zhou

derek-zhou

I use Origin header alone in production. Besides what you mentioned, there is at least one more problem with CSRF tokens nowadays because:

  • I store all session data server-side and only set a random key as the session cookie. (pretty common practice)
  • I have forms in public accessible pages (pretty common practice)
  • Bots are pounding those pages non-stop ((what can I say?)

By not generating and storing CSRF tokens, I avoided thrashing my session storage.

Where Next?

Popular in Proposals: Ideas Top

sevensidedmarble
Hello all, Apologies if this has been proposed before I guess, but I have a very simple one: With the increasing importance of LV, I th...
New
munksgaard
I’m copying and pasting this issue from @Terbium-135 here verbatim, because I would be interested in such a feature as well, and because ...
New
dimitarvp
To @jonatanklosko and @the-mikedavis: I see that there is a Rust crate at crates.io: Rust Package Registry but it is pointing at https:/...
New
dkuku
This is a proposal to make the map key mismatch errors a bit better: Every time I have a typo It’s very challenging for me even when I u...
New
benkimpel
Background I work at a hedge fund and our traders need highly dynamic UIs (think splitters, tabbed panels, tree lists, enormous data grid...
New
sodapopcan
So after complaining about this for the third or fourth time on this forum, I figured I should make a proposal. TL;DR with can be hard t...
New
zachdaniel
Something we do in various Ash packages is provide routes that the user forwards to in their own application. This is because we are deri...
New
calebjosue
I am reading (Once more) the Phoenix web framework documentation, in the From endpoint to views section contained in the Request life-cyc...
New
engineeringdept
In 2026 double submit/session tokens are no longer necessary to prevent against CSRF attacks. Instead, we can use the Sec-Fetch-Site head...
New
pierrelegall
Problem Currently, List.first/2 and List.last/2 return a default value (or nil) when the list is empty. However, there are cases where an...
New

Other popular topics Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54250 245
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New

We're in Beta

About us Mission Statement