Skip to content

Instantly share code, notes, and snippets.

@coyotespike
Created June 25, 2015 16:49
Show Gist options
  • Save coyotespike/c02c0c3ed56944d28737 to your computer and use it in GitHub Desktop.
Save coyotespike/c02c0c3ed56944d28737 to your computer and use it in GitHub Desktop.
CSRF in Clojure/ClojureScript
;; There are three parts to the problem:
;; (1) putting the token on the page on the server-side,
;; (2) getting it off on the client-side,
;; (3) and then POST-ing it with the request.
;;;; One could also GET and then POST using a route, but that makes the CSRF token useless.
; 1. Putting the token on the page.
; handler.clj
(def home-page
(html
[:html
[:head
[:meta {:charset "utf-8"}]
[:meta {:name "viewport"
:content "width=device-width, initial-scale=1"}]
; [:script {:type "javascript"} (def csrf {{csrf-token}})]
; [:meta {:csrf-token *anti-forgery-token*}]
; [:meta {:csrf-token (generate-string {:csrf-token *anti-forgery-token*})}]
; [:meta {:csrf-token (anti-forgery-field)}]
;;; Note that (anti-forgery-field) is a Ring function to generate the right HTML
(include-css "css/vendor/bootstrap.min.css")
(include-css "css/flat-ui-pro.css")]
[:body
[:div#app]
(include-js "/js/vendor/jquery.min.js"
"//code.jquery.com/ui/1.11.2/jquery-ui.js"
"//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css"
"/js/vendor/video.js"
"/js/flat-ui-pro.min.js"
"/js/app.js")]]))
;; 2. Getting the token off the page; selecting it.
;; db.cljs
;; Attempt the First. Uses the cljs-http library.
(defn save-stuff []
(http/post
"/submit"
{:name name
"value[]" (map :text msgs)}
:headers {"X-CSRF-Token"
csrf-token}}))
;; Attempt the Second.
(js/$
(fn []
(def anti-forgery-token
(.attr (js/$ "#__anti-forgery-token") "value"))))
;; Attempt the Third. Actually for some ungodly reason this returns a TypeError,
;; saying save-stuff below is undefined.
;; Uses the dommy library.
(def csrf-token (attr (sel1 "meta[name='csrf-token']")
"content"))
;; 3. Sending the token with the request. Uses cljs-ajax, and cljs-http libraries.
(defn save-stuff []
(ajax/POST "/submit" {:headers {:__anti-forgery-token csrf-token}}))
; (http/post "/submit" {:params {:message "hello world"} :headers {"x-csrf-token" (.-value (.getElementById js/document "token"))}}))
; (ajax/POST "/submit" {:headers {":__anti-forgery-token" (.-value (.getElementById js/document "token"))}}))
;; Another attempt.
(defn save-stuff []
(let [anti-forgery-token ($ :#__anti-forgery-token)]
(ajax/POST "/submit" {:headers anti-forgery-token})))
;; Final attempt.
(defn CSRFProtection []
(let [anti-forgery-token (attr (sel1 "meta[name='csrf-token']") "content")]
(if anti-forgery-token
xhr.setRequestHeader('X-CSRF-Token', anti-forgery-token))))
(defn save-stuff []
(CSRFProtection)
(ajax/POST "/submit"))
@miclill
Copy link

miclill commented Oct 9, 2016

Thanks for sharing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment