Spring 未找到安全 4 curl csrf 令牌

Spring Security 4 curl csrf token not found

我知道这个问题以前被问过很多,它适用于很多不同的方式,基于我已经在网上和这里问过的问题,我的问题多于我的答案。

所以,我有一个 Spring MVC 4.0 RESTful web-service,我知道它工作正常。我知道它工作正常,因为它通过了我的单元测试。增加安全性的单元测试和作为测试安全性一部分的 "csrf()" 使其工作。我确实注意到添加了这条数据:

Parameters = {_csrf=[435f9968-f643-47e9-9d15-23a5cb361b1d]}

RESTful web-service 使用 Spring Security 4 保护,默认启用 csrf 保护。所有带有 GET 的 web-service 都很好用,正是 POST 阻碍了我的 403 错误。

这是我要实现的卷曲:

curl \
-d '{"SiteId\:"548","SubjectId":TEST_sub","description":"TEST_des"}' \
--cookie "csrftoken=?????????????" \
--cookie "JSESSIONID=openam~A7FF59011F982FBB91C2F908E143327D" \
--cookie  "iPlanetDirectoryPro=AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*; path=/; domain=.mydomain.net" \
-H "X-CSFRToken: ??????" -H "Accept: */*" -H "Content-Type: */*" \
-H "openam-token: AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*" \
https://spring.mydomain.net/api/subject/build

所以,我知道 -d 参数明确地执行 POST; 我知道我的应用程序需要 iPlanetDirectoryPro 的 --cookie 我知道 -H 表示接受,Content-Type 和 openam_token 都是必需的。

我困惑的是: csfr 令牌的 -cookie ... 我从哪里获取数据? session id 或 JSESSIONID 的 -cookie? 当我第一次登录 web-site 时,我有一个 cookie:

JSESSIONID=openam~A7FF59011F982FBB91C2F908E143327D; path=/sso/; domain=spring-auth.mydomain.net; Secure; HttpOnly

现在说到 header: 是 X-CSFR-TOKEN 还是 X-CSFRToken ...我都看过了。

我有一个 SimpleCORSFilter,但是这个 header 不是允许的之一,有必要吗?我可以将它添加到可接受的 header 列表中。

我担心将 _csfr 放入 JSON 数据中。如果我添加了 Jackson 映射器,恐怕 web-service 将无法工作,因为 _csrf 没有匹配的 object,所以如果我这样做的话,我只是假设将它保留在外面.

所以,我在 curl 上做了很多试验和错误,但我今天运气不太好。当我确实让 curl 工作时,我必须将它传递给在 UI 上工作的承包商。他们正在使用 JavaScript 创建对 back-end 的 AJX 调用,因此他们可以将他们需要的任何东西传回 URL、post 数据,并且他们可以添加任何 headers 或 cookie,他们需要传回数据。我把这个留给他们去弄清楚。

任何能让我的 curl 正常工作的帮助都会很棒。谢谢!

更新: 当用户登录到我的应用程序时,我们使用 SiteMinder 示例的衍生版本。 也就是说,当我们成功通过身份验证时,我们会从 OpenAM 获取一个 cookie。然后我们使用 siteminder 示例调用 CustomUserDetailsS​​ervice,它使用该 cookie 调用 OpenAM 并获取用户名。然后我们对该用户名进行数据库查找以获取该用户的角色。在 none 中,我们是否取回了任何类型的 csrf 令牌。因此,对于我在 Whosebug 上看到的所有示例,没有 csrf 令牌可供我传回。我添加了以下 RESTful web-service.

@RequestMapping(value = "/csrf-token", method = RequestMethod.GET)
public @ResponseBody String getCsrfToken(HttpServletRequest request)
{
    CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
    return token.getToken();
}

我可以随时成功调用此 URL 并获得一个令牌 return 返回给客户端。例如:“45757c25-1af7-40d3-ab8b-1a9cd823efc5”

所以,我正在两个地方对此进行测试:Firefox 的 RESTClient 和 curl ...

在 RESTClient 中,我可以发出请求并获得一个 csrf 令牌,然后我尝试将其放入 RESTClient 中,如下所示:

URL: https://spring.mydomain.net/api/subject/build?_csrf=[45757c25-1af7-40d3-ab8b-1a9cd823efc5]
Headers:  
openam_token: AQIC5wM2LY4SfczkVMBTIq4pyjcec7QkyN0PJbY3NdmF8WE.*AAJTSQACMDE.*
X-CSRF-TOKEN: [45757c25-1af7-40d3-ab8b-1a9cd823efc5]

我还需要什么吗,因为它还没有工作。

卷曲:

curl \
-d '{"SiteId\:"548","SubjectId":TEST_sub","description":"TEST_des"}' \
--cookie "csrftoken=45757c25-1af7-40d3-ab8b-1a9cd823efc5" \
--cookie "JSESSIONID=openam~A7FF59011F982FBB91C2F908E143327D" \
--cookie  "iPlanetDirectoryPro=AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*; path=/; domain=.mydomain.net" \
-H "X-CSFR-TOKEN: 45757c25-1af7-40d3-ab8b-1a9cd823efc5" 
-H "Accept: */*" -H "Content-Type: */*" \
-H "openam-token: AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*" \
https://spring.mydomain.net/api/subject/build

再说一次,我缺少什么来完成这项工作????

我是否必须以某种方式组合我在 RESTClient 中的调用以获取此令牌,然后再到我的 POST?我如何在卷曲中结合这些?我知道每个 session 有一个 csrf 令牌,我想知道我可以拨打一个电话并获取此令牌,然后在下一个请求中使用它以传回 POST.

我不做 front-end,我们有另一家公司正在处理 UI 和 Ajax 电话,我希望能够测试我的 web-service 在我把它传递给他们之前打电话给他们。

再次感谢!

我认为这不能完全回答您的问题,但这是我添加 csrf 令牌的方法:

$(function () {
    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
    $(document).ajaxSend(function(e, xhr, options) {
        xhr.setRequestHeader(header, token);
    });
});

我查看了我的一个请求 headers 及其 "X-CSRF-TOKEN"

至于 curl,我找到了其他测试方法,通常是在单独的测试配置中禁用 CSRF。

经过多次尝试和错误的努力,我终于找到了如何使这项工作成功的方法。

根据之前的帖子,我有一个正确的想法,让我自己的控制器成为 return 一个令牌,这在上面突出显示。当我调用该服务以获取令牌时,我还确保我获取了 JSESSION 的 cookie。那是请求请求的 session,所以我必须确保在取回令牌后我抓住了它:

Cookie:  JSESSIONID=3A74721AD18E758D7B8DC54FB32A6515; Path=/services/; HttpOnly
csrf_token: db7e3100-bd2d-4ecf-8c0d-20b8b4e17b20

现在,无论是使用 Firefox RESTClient 还是使用 curl,您都需要两件事:

curl \
-d '{"SiteId\:"548","SubjectId":TEST_sub","description":"TEST_des"}' \
--cookie '\JSESSIONID=3A74721AD18E758D7B8DC54FB32A6515;' \
--cookie  "iPlanetDirectoryPro=AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*; path=/; domain=.mydomain.net" \
-H "X-CSFR-TOKEN: db7e3100-bd2d-4ecf-8c0d-20b8b4e17b20" 
-H "Accept: */*" -H "Content-Type: application/json" \
-H "openam-token: AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*" \
https://spring.mydomain.net/api/subject/build

请注意,JSESSION id 的 cookie 来自我首先获得 csrf 令牌 (db7e3100-bd2d-4ecf-8c0d-20b8b4e17b20) 的请求。 请注意,我确实需要 X-CSFR-TOKEN 来包含令牌,并且我在 SimpleCORSFilter 中启用了 header。

所以,这成功了!!!!我能够将令牌正确传递给 URL,并且我可以看到他记录了 int。能看到controller的访问,以及我传入的数据

REST 控制器定义为:

@RequestMapping(value = "/build", method = RequestMethod.POST, produces = "application/json", headers = "Content-Type=application/json")
public MyEntity build(@RequestBody SubjectImportDTO subjectImportDTO)
{
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    User user = null;
    if (principal instanceof User)
    {
        user = ((User) principal);
    }
    MyEntity entity = service.build(subjectImportDTO);
    return entity;
}

现在,URL 被找到,被调用,在后端工作,并准备好 return 一个实体......但是我从 curl 或火狐 REST 客户端。我认为如果我们甚至无法找到 REST 端点开始,就会产生 404 错误,所以这是我的另一个问题。