I copied some old code that was working in compojure 1.1.18 and other old libs, but using the latest versions I can't get it to work.
Here's my minimal example code copied from the minimal example here to demonstrate that with latest ring and compojure libraries, I get an error when I send an http POST
, even with the header set.
lein ring server
to start it, then do
curl -X GET --cookie-jar cookies "http://localhost:3000/"
which results in something like this:
{"csrf-token":"7JnNbzx8BNG/kAeH4bz1jDdGc7zPC4TddDyiyPGX3jmpVilhyXJ7AOjfJgeQllGthFeVS/rgG4GpkUaF"}
But when I do this
curl -X POST -v --cookie cookies -F "[email protected]" --header "X-CSRF-Token: 7JnNbzx8BNG/kAeH4bz1jDdGc7zPC4TddDyiyPGX3jmpVilhyXJ7AOjfJgeQllGthFeVS/rgG4GpkUaF" http://localhost:3000/send
I get <h1>Invalid anti-forgery token</h1>
Am I doing something wrong?
The code I borrowed was intended to answer this question.
edited. We recently had a pentest running and one security flaw that was reported is that CSRF-Tokens can be reused over multiple requests.
Anti-Forgery TokensOne token is sent as a cookie. The other is placed in a hidden form field. The tokens are generated randomly so that an adversary cannot guess the values. When the client submits the form, it must send both tokens back to the server.
Stealing Anti-CSRF Tokens: When CSRF tokens are passed as cookie parameters without Secure and HTTPOnly flags, an attacker can potentially steal the CSRF token via XSS or other attacks.
CSRF tokens are unique and validated on GET/POST requests to ensure there is no cross site requests being made in Salesforce. Once a request is made, the auto generated token is validated to confirm if the request is from the UI and not an intiated request from another site.
The problem was that ring-defaults
(which replaces the compojure.handler
namespace in compojure >= 1.2) automatically uses ring anti-forgery
in the usual mode of use:
(defroutes app-routes
(GET "/" [] (generate-string {:csrf-token
*anti-forgery-token*}))
(POST "/send" [email] "ok")
(resources "/")
(not-found "Not Found"))
(def app
(-> app-routes
(wrap-defaults site-defaults)))
So two anti-forgery tokens were being generated and the GET
request provided the invalid one. Removing the wrap-anti-forgery
line fixed the problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With