未找到Spring Security 4 curl csrf令牌

时间:2016-01-29 18:33:40

标签: spring rest curl csrf-protection

我知道这个问题之前已经被问了很多,并且它采用了很多不同的方式,并且基于我已经在互联网上提出的问题,在这里,我有更多的问题而不是我的答案。

所以,我有一个Spring MVC 4.0 RESTful网络服务,我知道它可以正常工作。我知道它工作正常,因为它通过了我的单元测试。单元测试,增加了安全性,“csrf()”作为测试安全性的一部分,使其工作。我注意到这条数据已添加:

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

RESTful Web服务受Spring Security 4保护,默认启用csrf保护。使用GET的所有Web服务都运行良好,这是因为403错误而阻碍我的POST。

以下是我试图实施的卷曲:

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的Accept,Content-Type和openam_token都是必需的。

我感到困惑的是: csfr令牌的-cookie ...我从哪里获取数据? 会话ID或JSESSIONID的-cookie? 当我第一次登录我的网站时,我有一个像以下的cookie:

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

现在谈到标题: 是X-CSFR-TOKEN还是X-CSFRToken ......我见过两者。

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

我担心将_csfr放入JSON数据中。如果我添加它,使用Jackson映射器,恐怕web服务不起作用,因为_csrf没有匹配的对象,所以我只是假设如果我这样做,就把它保留在那里。

所以,我从curl做了很多试验和错误,今天我运气不好。当我确实让卷曲工作时,我必须将其传递给在UI上工作的承包商。他们使用JavaScript来创建后端的AJX调用,因此他们可以在URL中传递他们需要的任何内容,发回数据,并且他们可以添加他们传回数据所需的任何标题或cookie。我留下让他们弄清楚。

让我的卷发工作的任何帮助都会很棒。谢谢!

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

@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并将令牌返回给客户端。例如:“45757c25-1af7-40d3-ab8b-1a9cd823efc5”

所以,我在两个地方测试它:RESTClient for Firefox和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?如何将这些组合在卷曲中?我知道每个会话有一个csrf令牌,我想知道我可以进行一次调用并获得此令牌,然后在下一个请求中使用它来传回POST。

我没有做前端,我们有另一家公司正在进行UI和Ajax调用,我希望能够在将它传递给他们之前测试我的Web服务调用。

再次感谢!

2 个答案:

答案 0 :(得分:1)

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

我有一个正确的想法,基于之前的帖子让我自己的控制器返回一个令牌,这在上面突出显示。当我调用该服务来获取令牌时,我也确保抓住了JSESSION的cookie。这是请求请求的会话,因此我必须确保在获得令牌后抓住它:

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中启用了该头。

所以,这很有用!!!!!我能够将令牌正确传递给URL,我可以看到他记录的内容。我可以看到对控制器的访问以及我传入的数据。

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,被调用,后端工作,并准备返回一个实体......但我从curl或Firefox RESTClient得到404错误。我认为如果我们甚至找不到REST端点,就会产生404错误,所以这是我的另一个问题。

答案 1 :(得分:0)

我不认为这完全回答了您的问题,但我在这里添加了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);
    });
});

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

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