sta*_*uxe 12 spring-mvc csrf spring-security thymeleaf
我在我的Spring MVC应用程序中使用Spring Security 3.2.3并获得一些意外行为.
根据这里的文档,应该可以${_csrf.token}在我的html的meta标签中使用:
<meta name="_csrf" content="${_csrf.token}" />
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}" />
Run Code Online (Sandbox Code Playgroud)
从中我使用JQuery提取"内容"的值,并使用AJAX将其放入Request Header.
出于某种原因,Spring Security不会将其"转换"为实际令牌,它只是作为文字字符串"$ {_ csrf.token}"发送到标头中.
${_csrf.token}根据文档尝试在隐藏输入中使用的替代路径,然后我尝试通过检查输入的值来检查令牌评估的内容,但它仍然只是纯文本"$ {_ csrf.token}".
由于Spring Security似乎没有生效,我是否缺少某种配置?我目前正在使用准系统Spring Security Java配置(而不是xml),如下所示:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
我知道配置被调用,因为我在其中放入了一个调试语句,因此我假设CSRF保护确实已启用,因为它应该是默认的.
我意识到语法"$ {}"是JSP表达式语言,我目前正成功地用它来评估Thymeleaf对象的上下文,例如:
th:object="${context}"
Run Code Online (Sandbox Code Playgroud)
所以我尝试在元标记的"内容"前添加"th:",如下所示:
<meta name="_csrf" th:content="${_csrf.token}"/>
Run Code Online (Sandbox Code Playgroud)
但它导致一个例外,无法评估:
评估SpringEL表达式的异常:"_csrf.token"
我认为这里的关键可能是弄清楚如何在我看来正确评估表达式.
我终于解决了这个问题,但它基本上需要重写Spring Security.这里充满了荣耀.
首先,我遵循的Eyal卢浦的精彩的博客贴子的建议在这里,但我不得不把它调整到我的情况,因为我的AJAX的要求.
至于Thymeleaf的情况,关键的花絮被隐藏在Thymeleaf论坛的档案中 - 臭名昭着的第7期.
https://github.com/thymeleaf/thymeleaf-spring/issues/7#issuecomment-27643488
Thymeleaf自己的创始人的最后评论说:
th:action...检测何时将此属性应用于标记 - 无论如何应该是唯一的地方 - 并且在这种情况下调用RequestDataValueProcessor.getExtraHiddenFields(...)并在结束标记之前添加返回的隐藏字段.
这是我需要让令牌工作的关键短语.不幸的是,为什么th:action还要开始getExtraHiddenFields,这是完全不明显的,但无论如何,它确实如此,这才是最重要的.
所以对于那些在Thymeleaf + Spring Security CSRF + AJAX POST中苦苦挣扎的人来说,这里有我的步骤(这是相当多的,但这些是解决它的高级概念):
实现Spring接口RequestDataValueProcessor并在Spring Security的XML配置中注册它,这样你就可以覆盖方法getExtraHiddenFields,它允许你在HTML中插入一个隐藏的输入字段(当然还有令牌).令牌本身是使用Java.Util UUID生成的.
使用JQuery,从该隐藏字段中读取值并设置Request Header的"X-CSRF-Token"属性,以便通过HTTP发送它.不可能简单地将令牌留在隐藏的输入字段中,因为我们没有做表单提交,而是使用AJAX POST来调用服务器端的方法.
扩展Spring的HandlerInterceptorAdapter并将其注册为拦截器,以便每次完成POST方法时,都会调用服务器端的"preHandle"方法,以便它可以将请求令牌(从上一步骤中的HTTP头提取)与会话的令牌(应该是相同的!).执行此检查后,它可以允许请求通过或返回错误.
小智 5
我认为我从与您相同的源文章开始,并且与您一样“您应该能够”添加答案。我以不同的方式与之抗争。我让 Thymeleaf 给了我想要的答案。
<meta name="_csrf" th:content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
Run Code Online (Sandbox Code Playgroud)
Thymeleaf 将属性“content”与请求的 Spring EL 内容放在一起。然后我使用提供的 JavaScript/JQuery 将元标记中的信息直接提取到 CSRF 标头中。
| 归档时间: |
|
| 查看次数: |
31216 次 |
| 最近记录: |