How do you do CSRF protection in your Clojure webapps?

The solution I know of is ring.middleware.anti-forgery/wrap-anti-forgery , but it has some gotchas and magic necessary including the order in which you fire it, the configuration of your session, etc. Missteps are tricky to debug and result in constant “Invalid anti-forgery token” errors. Sometimes I end up disabling CSRF altogether in order to just get something working. Does anyone have preferred methods, or know the magic key to always getting the ring version to work?

I haven’t had any issues with ring.middleware.anti-forgery. I always use an encrypted session cookie (via this helper, and there is also a secret-key function that I use to create the keys). Just make sure that

  • The session middleware is wrapped after the anti-forgery: (-> f wrap-anti-forgery wrap-your-session-middleware)
  • Never return a response with :session nil. If you need to log a user out or something, do it by clearing just the relevant keys: {:session (dissoc session :auth)} where session == (:session request).
  • Of course, remember to include the anti-forgery-field in every form.
2 Likes

I wrote a small library that provides CSRF tokens and a cookie-based encrypted session store (using AWS KMS). It’s based on the Rails session store.

I wasn’t using Ring for the project I was working on when I wrote it, but I suspect it wouldn’t be too hard to turn it into a Ring middleware. At the very least, maybe it will give you some inspiration.

This article is a good deep-dive into how Rails CRSF protection works: https://medium.com/rubyinside/a-deep-dive-into-csrf-protection-in-rails-19fa0a42c0ef

1 Like

Excellent readings! Thanks!

Those are incredibly useful guidelines with the anti-forgery middleware. Thank you.