Any request that isn't a HEAD or GET request will require an anti-forgery token, or an "access denied" response will be returned. The token is bound to the session, and accessible via the *anti-forgery-token* var.
By default the middleware looks for the anti-forgery token in the "__anti-forgery-token" form parameter, which can be added to your forms as a hidden field.
The middleware also looks for the token in the "X-CSRF-Token" and "X-XSRF-Token" header fields, which are commonly used in AJAX requests.
So when I use cljs-ajax to post to my APP I get an Invalid anti-forgery token error.--
Despite there being dozens of posts about this issue, none of them have a solution that seems to work if you started your project using this:lein new reagent myapp
The first post that comes up as a "solution" actually recommends disabling CSRF protection, which seems like just avoiding the problem rather than solving it, but they don't actually tell you how to do that either!After 4 hours of searching for any solution, I admit that the only fix that I found was this:(ns reformdems.middleware(:require [ring.middleware.defaults :refer [site-defaults wrap-defaults]][ring.middleware.json :refer [wrap-json-params]][prone.middleware :refer [wrap-exceptions]][ring.middleware.reload :refer [wrap-reload]]))(defn wrap-middleware [handler](-> handler(wrap-defaults (merge site-defaults {:security {:anti-forgery false} :params {:keywordize true}}))wrap-exceptionswrap-reloadwrap-json-params))
By setting :security :anti-forgery to false, I no longer get the Anti-Forgery issue. But yeah, this isn't a real solution.What I'm looking to do is get one of the solutions involving "*anti-forgery-token*" or (anti-forgery-field) working.Unfortunately, these instructions here, don't work, and only produce hard to understand errors:
https://github.com/ring-clojure/ring-anti-forgery
As a side note, it's really confusing when all the libraries use this language:(use 'ring.util.anti-forgery)
(anti-forgery-field)Meanwhile "use" is not in any of the code generated using lein. I would expect this would be the proper way to use the libraries:(ns myapp.server(:require[ring.util.anti-forgery) :refer [anti-forgery-field]]))
Of course, I'm just guessing at that refer command, but my point is this inconsistency makes me feel like I'm looking at solutions designed for an older version of Clojure or something?I'm also concerned that given a library [ring/ring-anti-forgery "1.0.1"] there is no way to intuitively know how to "require" that library in your code. In the above situation the word "util" gets added when requiring it..Anyways, my main question is this:
What is the modern way to do CSRF protection?
Secondly, I'm concerned I'm doing something wrong - ring.middleware feels like a magical thing where you apply wrappers, and then stuff just magically works. I'm not a big fan of magic, I want to be able to see a pathway for finding a solution, not just google around and figure out a wrapper needs to be added.. Any recommendations on that front?Thanks!Seth
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Okay, armed with the new clarity, I felt embolden to tackle this once more. Here's the next steps for those trying to tack CSRF protection onto a Reagent project created with lein new reagent.In handler.clj - you'll add the ring.middleware.anti-forgery and refer to *anti-forgery-token*(ns myapp.handler
(:require
[ring.middleware.anti-forgery :refer [*anti-forgery-token*]]))Then, lower down in your code you'll have something like this:(html5
[:head
[:meta {:csrf-token *anti-forgery-token*}]
This will create a token for you.Now I haven't gone the rest of the distance with this problem so I can't say that it's all downhill from here, it's possible I'm messing up and re-generating a token that won't match what's already matched in the session. Let me know if that's what I'm doing :(
But the next thing I would do, is in /cljs/myapp/core.cljs - I would find a way to pull in this token from the meta tag (maybe by using vanilla javascript) and then add it to my post commands.A couple things that confused me:It's not obvious that you have to add ring.middleware.anti-forgery to handler.clj, because in the examples in the documentation we're pulling that in so we can do "wrap-anti-forgery" in our middleware.clj. However, this is done automatically using ring.middleware.defaults, in the middleware.clj file, so it looks like ring.middleware.anti-forgery doesn't need to be anywhere.However, without ring.middleware.anti-forgery, it seems *anti-forgery-token* isn't bound.. once you require that, that it exists!Let me know if my assumptions are wrong on this - it's possible I'm going down the wrong direction and that *anti-forgery-token* is actually stored in the session somewhere, but I have no idea how to access the session at this point.. That sounds like a whole nother bag of worms.EpilogueThe turning point for me was realizing that the ring-defaults file is ridiculously easy to comprehend on Github. I'm so used to php projects where inspecting classes is basically impossible - in order to understand one thing, you need to understand 12 other things, which in turn require an understanding of 3 other things etc. To open up defaults.cli and see that site-defaults is just a simple map, literally made me sigh in relief :pI'm beginning to grasp the structure of packages of namespaces, which makes seeing into the code easier. It strikes me Clojure is a system which dramatically rewards investment into it's fundamental building blocks. I feel like I have a lot to learn, but it's all worth learning. Thanks!