无法使用Spring Security创建CSRF令牌 [英] Can't create CSRF token with Spring Security

查看:358
本文介绍了无法使用Spring Security创建CSRF令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Spring MVC应用程序中使用Spring Security 3.2.3,并且出现了一些意外的行为。

I am using Spring Security 3.2.3 in my Spring MVC application and getting some unexpected behavior.

根据此处的文档,应该可以在我的html的meta标签中使用 $ {_ csrf.token}

According to the documentation here, it should be possible to use ${_csrf.token} in the meta tags of my html:

<meta name="_csrf" content="${_csrf.token}" />
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}" />

我从此处使用JQuery提取 content的值,然后使用AJAX将其放入请求标头中

From where I extract the value of "content" using JQuery and place it into the Request Header using AJAX.

尽管出于某种原因,Spring Security不会将其转换为实际的令牌,而只是将其作为文本字符串 $ {_ csrf发送到标头中.token}。

For some reason though, Spring Security doesn't "convert" this into an actual token, it just gets sent into the header as a literal string "${_csrf.token}".

尝试在隐藏输入中使用 $ {_ csrf.token} 的另一种方法到文档,然后我尝试通过检查输入的值来检查令牌的计算结果,但仍然只是纯文本 $ {_ csrf.token}。

Trying the alternate route of using ${_csrf.token} in a hidden input according to the documentation, I then tried to check what the token evaluates to by checking the input's value, but it's still just plain text "${_csrf.token}".

既然似乎Spring Security无效,我是否缺少某种配置?我目前正在使用准系统Spring Security Java配置(而不是xml),如下所示:

Since it seems that Spring Security isn't in effect, am I missing some kind of configuration? I am currently using a barebones Spring Security Java configuration (as opposed to xml) as shown here:

import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.*;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .csrf();
      }
}

我知道由于我放置了调试程序,configure正在被调用语句中,因此我假定确实启用了CSRF保护,因为默认情况下应该启用它。

I know configure is getting called since I put a debug statement in it, so I assume that CSRF protection is indeed enabled since it should be by default.

我意识到语法 $ {}是JSP表达式语言,并且我目前正在成功地使用它来将上下文评估为Thymeleaf对象,例如:

I realize that the syntax "${}" is JSP Expression Language, and I am currently successfully using it to evaluate the context into an object with Thymeleaf, for example:

th:object="${context}"

因此,我尝试在meta标签的内容前面添加 th:,如下所示:

So I tried adding "th:" in front of the meta tag's "content" like so:

<meta name="_csrf" th:content="${_csrf.token}"/>

但这会导致无法评估的例外:

But it results in an exception that this cannot be evaluated:


评估SpringEL表达式的异常: _csrf.token

Exception evaluating SpringEL expression: "_csrf.token"

我认为关键

推荐答案

我终于解决了这个问题,但是它解决了这个问题。基本上需要重写Spring Security。

I finally solved this problem, but it basically required rewriting Spring Security. Here it is in all its glory.

首先,我遵循Eyal Lupu出色的博客文章此处,但是由于我的AJAX要求,我不得不根据自己的情况进行调整。

First, I followed the suggestions in Eyal Lupu's great blog post here, but I had to tweak it to my situation because of my AJAX requirement.

关于Thymeleaf的情况,关键花絮隐藏在Thymeleaf论坛的档案中-臭名昭著的第7期。

As for the Thymeleaf situation, the key tidbit is hidden away in the archives of the Thymeleaf forums - Infamous Issue 7.

https://github.com/thymeleaf/thymeleaf-spring/issues/7# issuecomment-27643488

Thymeleaf的创建者本人最后发表的评论是:

The last comment by the creator of Thymeleaf himself says that:


th:action ...检测何时将此属性应用于
标记-无论如何,它应该是唯一的位置- -,在这种情况下
调用 RequestDataValueProcessor.getExtraHiddenFields (...),并在结束标记之前添加
返回的隐藏字段。

th:action ... detects when this attribute is being applied on a tag --which should be the only place, anyway--, and in such case calls RequestDataValueProcessor.getExtraHiddenFields(... ) and adds the returned hidden fields just before the closing tag.

那是我需要令牌才能工作的关键词。不幸的是,为什么 th:action 也将启动 getExtraHiddenFields 尚不完全清楚,但是无论如何,这就是

That was the key phrase I needed to get the token to work. Unfortunately it's completely not obvious why th:action would also kick off getExtraHiddenFields, but at any rate it does, and that's what matters.

因此,对于任何在Thymeleaf + Spring Security CSRF + AJAX POST上苦苦挣扎的人来说,这是我的步骤(虽然可以节省很多,但是这些都是很高的级别的概念来解决它):

So for anyone struggling with Thymeleaf + Spring Security CSRF + AJAX POST, here are my steps (this is paring it down quite a bit but these are the high-level concepts to solve it):


  1. 实现Spring接口RequestDataValueProcessor并在Spring Security的XML配置中注册它,以便您可以覆盖getExtraHiddenFields方法,该方法使您可以将隐藏的输入字段插入HTML(当然带有标记)。令牌本身是使用Java.Util UUID生成的。

  1. Implement the Spring interface RequestDataValueProcessor and register it in Spring Security's XML config so you can override the method getExtraHiddenFields, which allows you to insert a hidden input field into the HTML (with the token of course). The token itself is generated with a Java.Util UUID.

使用JQuery,从该隐藏字段中读取值,然后设置请求标头的 X-CSRF-令牌属性,以便通过HTTP发送。无法将令牌仅保留在隐藏的输入字段中,因为我们没有执行表单Submit,而是使用AJAX POST来调用服务器端的方法。

With JQuery, read the value from that hidden field and set the Request Header's "X-CSRF-Token" attribute so that it gets sent over HTTP. It's not possible to simply leave the token in the hidden input field because we are not doing a form Submit, instead we use AJAX POST to call methods on the server side.

扩展Spring的HandlerInterceptorAdapter并将其注册为拦截器,以便每次执行POST方法时,都会调用服务器端的 preHandle方法,以便可以比较请求令牌(从上一步的HTTP标头中提取) )添加到会话的令牌(应该相同!)。完成此检查后,它可以允许请求通过或返回错误。

Extend Spring's HandlerInterceptorAdapter and register it as an interceptor so that every time a POST method is done, the "preHandle" method on the server side is called so it can compare the request token (extracted from the HTTP header in the previous step) to the session's token (should be the same!). After it does this check, it can either allow the request to go through or return an error.

这篇关于无法使用Spring Security创建CSRF令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆