2

我正在使用试剂和组合物来制作玩具 web 应用程序,但我无法弄清楚为什么我的服务器没有发送 CSRF cookie。其他答案和几篇博客文章似乎暗示 compojure 的默认设置现在发送 CSRF 令牌,并且手动重新发送它实际上是一个错误。当我尝试点击 POST/art端点时,我得到了 403 Forbidden 响应。所有页面都没有获得带有 CSRF 令牌的 cookie,因此我无法通过 POST 请求发送它。有什么建议吗?

;;server.clj

(ns my-app.server
  (:require [my-app.handler :refer [app]]
            [environ.core :refer [env]]
            [ring.adapter.jetty :refer [run-jetty]])
  (:gen-class))

 (defn -main [& args]
   (let [port (Integer/parseInt (or (env :port) "3000"))]
     (run-jetty app {:port port :join? false})))

;; handler.clj

(ns my-app.handler
  (:require [compojure.core :refer [GET POST defroutes]]
            [compojure.route :refer [not-found resources]]
            [hiccup.page :refer [include-js include-css html5]]
            [my-app.middleware :refer [wrap-middleware]]
            [environ.core :refer [env]]))


(defroutes routes
  (GET "/" [] loading-page)
  (GET "/about" [] loading-page)
  (GET "/art" [] loading-page)
  (POST "/art" request {:sent (:body request) :hello "world"})

  (resources "/")
  (not-found "Not Found"))

(def app (wrap-middleware #'routes))


;;middleware.clj

(ns stagistry.middleware
  (:require [ring.middleware.defaults :refer [site-defaults wrap-defaults]]
            [prone.middleware :refer [wrap-exceptions]]
            [ring.middleware.reload :refer [wrap-reload]]))

(defn wrap-middleware [handler]
  (-> handler
      (wrap-defaults site-defaults)
      wrap-exceptions
      wrap-reload))

我在这里将代码本身扔到了 github 上,因为我仍然看不出有什么问题。

4

2 回答 2

3

其他答案和几篇博客文章似乎暗示 compojure 的默认设置现在发送 CSRF 令牌,并且手动重新发送它实际上是一个错误。

(wrap-defaults site-defaults)应用环防伪中间件。这只会将 CSRF 令牌添加到每个环浏览器会话并在 POST 请求中查找令牌。如果令牌丢失,中间件将为403请求返回 a。将令牌添加到您的表单或 ajax/任何帖子请求中取决于您,自由的代价。:)

来自ring-anti-forgery文档:

默认情况下,令牌应位于名为“__anti-forgery-token”的表单字段中,或位于“X-CSRF-Token”或“X-XSRF-Token”标头中。

例如尝试添加这条路线:

(GET "/someform" request (html5 (ring.util.anti-forgery/anti-forgery-field)))

anti-forgery-field助手将添加一个以 CSRF 令牌作为其值的隐藏输入字段,如果表单发布,中间件将获取该字段。要直接访问令牌,您可以使用ring.middleware.anti-forgery/*anti-forgery-token*或在当前请求映射的会话中查找它:

(-> request :session :ring.middleware.anti-forgery/anti-forgery-token)

全局变量(以及扩展的帮助程序)绑定到处理程序上下文,但您不能从外部或同一上下文中的另一个线程访问它。

简单的 curl 标头示例:

  1. 获取 CSRF 令牌:

    $ curl -v -c /tmp/cookiestore.txt http://localhost:3000/someform
    

  2. 通过标头设置令牌并发布一些内容:

    $ curl -v -b /tmp/cookiestore.txt --header "X-CSRF-Token: ->token from prev. req<-" -X POST -d '{:foo "bar"}' localhost:3000/art
    
于 2016-03-08T05:24:16.940 回答
1

所以我找到了一个相关问题的答案,目前对我来说已经足够好了。我将 middleware.clj 切换site-defaultsapi-defaults不使用 CSRF 的位置。仍然好奇如何让 CSRF 在这里工作,但这对我正在做的事情并不重要。如果后来有人提出可行的修复方法,我会将其标记为正确的。

于 2016-03-08T03:17:09.623 回答