如何在调用环形REST路由的Clojure HTTP客户端中正确使用跨站点请求伪造预防?

如何在调用环形REST路由的Clojure HTTP客户端中正确使用跨站点请求伪造预防?,rest,clojure,csrf,middleware,ring,Rest,Clojure,Csrf,Middleware,Ring,我仍在学习Clojure(以及所有随附的库…),因此,如果我在无知中做了任何愚蠢的事情,请随时指出:-) 我无法从客户端代码通过POST方法调用REST端点。我的路由使用(ring.middleware.defaults/wrap-defaults site defaults)(我相信如果在生产中运行这样的代码,这是一个相当好的主意)。此包装器应用各种其他包装器,包括ring.middleware.anti-forgery/wrap-anti-forgery,它(除其他外)实现了跨站点请求伪造(

我仍在学习Clojure(以及所有随附的库…),因此,如果我在无知中做了任何愚蠢的事情,请随时指出:-)

我无法从客户端代码通过
POST
方法调用REST端点。我的路由使用
(ring.middleware.defaults/wrap-defaults site defaults)
(我相信如果在生产中运行这样的代码,这是一个相当好的主意)。此包装器应用各种其他包装器,包括
ring.middleware.anti-forgery/wrap-anti-forgery
,它(除其他外)实现了跨站点请求伪造(CSRF或XSRF)预防方案-默认(我正在使用)是一个

通过
GET
调用相同的REST端点工作正常(因为CSRF保护不应用于
GET
HEAD
OPTIONS
调用-请参阅
ring.middleware.anti-forgery/GET-request?
),但使用
POST
(或其他方法之一)导致403-无效防伪令牌响应

(如下面的示例代码所示)我知道如何将“X-CSRF-Token”或“X-XSRF-Token”头添加到HTTP请求中。(因为这是一个REST调用,所以我没有按照建议添加隐藏的“\uu anti-forgery-token”字段,尽管其中一个标题或表单字段可以满足包装器的要求-请参阅
ring.middleware.anti-forgery/default request token
)相反,如果我正确理解代码,我的问题源于这样一个事实:默认策略将上述令牌与会话令牌值进行比较,会话令牌值由
ring.middleware.anti-forgery.session/session-token
检索:

(defn-会话令牌[请求]
(进入请求[:会话:环.中间件.防伪/防伪令牌])
我不知道如何在HTTP客户端调用中正确设置会话信息。(任何HTTP客户端都足够了,因为上面提到的403结果是由中间件包装器生成的。因此,对于下面的演示,我使用简单的
ring.mock.request

下面是一些最基本的代码,显示了我到目前为止所拥有的内容。它定义路由和处理程序,然后尝试从单元测试调用它们

(ns question.rest
(:require[compoure.core:参考:全部]
[ring.middleware.defaults:参考[wrap defaults站点默认值安全站点默认值]]
[ring.middleware.anti-forgery:参考[*防伪令牌*]]
[clojure.test:参考:全部]
[ring.mock.request:as mock]))
(取消路线)
exmpl路由
(任何“/“[]”站点正常运行。”)
(获取“/aft”[](强制*防伪令牌*))
(def exmpl(包裹默认值exmpl路由站点默认值))
(deftest-test-mock-fail
(测试“POST-to-root路由”
(让[
;在普通的web应用程序中,视图/页面将从服务器获取,这将
;将防伪令牌包含在其中,并将此帖子作为一项操作。因此
;这里的自动变速箱油处理方式。。。
尾部(:主体(exmpl)(模拟/请求:获取)https://localhost:8443/aft")))
请求(->(模拟/请求:post)https://localhost:8443/")
(模拟/标题“X-CSRF-Token”尾部)
_(打印请求)
响应(exmpl请求)
_(println响应)
]
(是(=200(:状态响应));;403
(是(=“现场正常”。(:身体反应()())));;无效的防伪令牌
(println)
调用显示以下内容(应用了一些格式):

请求:

{:protocol“HTTP/1.1”,
:服务器端口8443,
:服务器名称“localhost”,
:remote addr“localhost”,
:uri“/post”,
:scheme:https,
:请求方式:post,
:标头{“主机”“本地主机:8443”,
“x-csrf-token”“”}
答复:

{:状态403,
:headers{“Content Type”“text/html;charset=utf-8”,
“X-XSS-Protection”“1;模式=块”,
“X-Frame-Options”“SAMEORIGIN”,
“X-Content-Type-Options”“nosniff”},
:正文“无效的防伪令牌”}

我可以找到的教程主要集中在
GET
方法上,并且似乎假设端点/路由将从HTML调用,HTML由服务器提供(包括会话信息)。所以我现在觉得有点卡住了。

对于REST API,您应该使用
API默认值
安全API默认值
而不是
站点默认值


防伪机制专为应用程序生成
表单的网站而设计,可以包含生成的令牌,作为表单提交
POST
的一部分发送回去——它不用于REST API。

谢谢!事后看来,这很明显,但很容易被忽略,因为我使用“默认值”包装来弥补我在HTTP和安全问题方面的知识差距(请注意:需要更多的学习)。现在我需要弄清楚如何为站点场景构建一些端到端集成测试:-)