Java 未找到预期的 CSRF 令牌。您的会话是否已过期 403

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28138864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 05:39:49  来源:igfitidea点击:

Expected CSRF token not found. Has your session expired 403

javaspring

提问by St.Antario

I'm trying to write my test spring security application with mkyong examples.

我正在尝试使用 mkyong 示例编写我的测试 spring 安全应用程序。

Spring Security: 4.0.0.RC1
Spring: 4.1.4.RELEASE

I have the following security config:

我有以下安全配置:

<http auto-config="true">
    <intercept-url pattern="/admin**" 
                    access="hasRole('ADMIN')"/>
    <form-login authentication-failure-url="/?auth_error" 
                        username-parameter="user" 
                        password-parameter="password" 
                        login-page="/"
                        default-target-url="/?OK"/>
<!-- <csrf/> -->
</http>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="mkyong" password="123456" authorities="ADMIN" />
        </user-service>
    </authentication-provider>
</authentication-manager>

login-page:

登录页面:

<html>
<body>
<form method="POST">
    <label for="user">User: </label>
    <input type="text" id="user" name="user" /> </br>
    <label for="password">Password: </label>
    <input type="text" name="password" id="password" /> </br>
    <input type="submit" /> 
</form>
</body>
</html>

Now, when I try to login I get 403 error page:

现在,当我尝试登录时,出现 403 错误页面:

Invalid CSRF Token 'null' was found on the request parameter 
'_csrf' or header 'X-CSRF-TOKEN'.

description:

描述:

Access to the specified resource (Invalid CSRF Token 'null' was
found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.) has been 
forbidden.

What's wrong, how can I fix that? I commented csrfin the config, but the error-message has to do with the csrf.

怎么了,我该如何解决?我csrf在配置中进行了评论,但错误消息与csrf.

回答by Todd

If you must disable it...

如果您必须禁用它...

In Spring Security 4, CSRF is enabled by defaultwhen using the XML configuration. Previously it was only enabled by default for the Java-based configuration.

在 Spring Security 4 中,使用 XML 配置时默认启用 CSRF。以前,它仅在默认情况下为基于 Java 的配置启用。

According to Section 14.4.2 of the Spring Security Documentation:

根据Spring Security 文档的第 14.4.2 节

As of Spring Security 4.0, CSRF protection is enabled by default with XML configuration. If you would like to disable CSRF protection, the corresponding XML configuration can be seen below.

从 Spring Security 4.0 开始,默认情况下使用 XML 配置启用 CSRF 保护。如果您想禁用 CSRF 保护,可以在下面看到相应的 XML 配置。

<http>
   ...
   <csrf disabled="true"/>
   ...
</http>

回答by Neil McGuigan

Disabling CSRF protection sounds like a bad idea, no?

禁用 CSRF 保护听起来是个坏主意,不是吗?

If you use Spring's Form Tag library the CSRF token will be automatically included. It will also HTML Escape form element values, which makes your site safer against XSS, and more correct.

如果您使用 Spring 的 Form Tag 库,CSRF 令牌将自动包含在内。它还将 HTML 转义表单元素值,这使您的站点更安全地抵御 XSS,并且更正确。

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> 

<form:form>
  <form:input...
</form:form>

Otherwise, add this to your form:

否则,将其添加到您的表单中:

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

回答by Yinghua

I had the same problem. I use thymeleaf and Spring boot, and got the CSRF token issue when I try to post data in a form.

我有同样的问题。我使用 thymeleaf 和 Spring boot,当我尝试在表单中发布数据时遇到了 CSRF 令牌问题。

Here is my working solution:

这是我的工作解决方案:

  1. Add this hidden input:

    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />

  2. In your WebSecurityConfig(which extends WebSecurityConfigurerAdapter), add a method:

    private CsrfTokenRepository csrfTokenRepository() 
    { 
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); 
        repository.setSessionAttributeName("_csrf");
        return repository; 
    }
    

    and add code in method configure():

    @Override
     protected void configure(HttpSecurity http) throws Exception {
         http.csrf()
         .csrfTokenRepository(csrfTokenRepository())
    
  1. 添加此隐藏输入:

    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />

  2. 在您的WebSecurityConfig(扩展WebSecurityConfigurerAdapter)中,添加一个方法:

    private CsrfTokenRepository csrfTokenRepository() 
    { 
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); 
        repository.setSessionAttributeName("_csrf");
        return repository; 
    }
    

    并在方法中添加代码configure()

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

I spent lot of time on this problem. Hope it can help someone who has the same problem.

我在这个问题上花了很多时间。希望它可以帮助有同样问题的人。

回答by Java_Fire_Within

To @St.Antario, Please use this code to enable CSRF in your code

致@St.Antario,请使用此代码在您的代码中启用CSRF

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("*/*").authorizeRequests()
                .antMatchers("/", "/login**").permitAll()
                .anyRequest().authenticated()
                .and().csrf().csrfTokenRepository(csrfTokenRepository())
                .and().addFilterAfter(csrfHeaderFilter(), SessionManagementFilter.class);
    }

    private Filter csrfHeaderFilter() {
        return new OncePerRequestFilter() {

            @Override
            protected void doFilterInternal(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain filterChain) throws ServletException, IOException {

                CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
                if (csrf != null) {
                    Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                    String token = csrf.getToken();
                    if (cookie == null || token != null
                            && !token.equals(cookie.getValue())) {

                        // Token is being added to the XSRF-TOKEN cookie.
                        cookie = new Cookie("XSRF-TOKEN", token);
                        cookie.setPath("/");
                        response.addCookie(cookie);
                    }
                }
                filterChain.doFilter(request, response);
            }
        };
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        //repository.setSessionAttributeName(("X-XSRF-TOKEN"));
        return repository;
    }
}

回答by Carlos Alberto Gonzalez

spring-security.xml

spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security.xsd
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <http pattern="/resources/**" security="none" />

    <http use-expressions="true">
        <intercept-url pattern="/login*" access="isAnonymous()" />
        <intercept-url pattern="/**" access="isAuthenticated()"/>
        <form-login
            login-page="/login"
            default-target-url="/home"
            authentication-failure-url="/login?error=true" /> 
        <logout
            logout-success-url="/login"
            delete-cookies="JSESSIONID" />
    </http>
    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="carlos" password="123" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
</beans:beans>

web.xml

网页.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml, /WEB-INF/spring-security.xml</param-value>
</context-param>

add add jsp login

添加添加jsp登录

<%@page session="true"%>

and input hidden:

并输入隐藏:

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />

回答by johnmin

What is your login page named Is it ending with .jsp

您的登录页面名称是什么 以 .jsp 结尾

If the login page is not ending with .jsp Spring framework doesn't evaluate the JSP or EL expressions

如果登录页面不以 .jsp 结尾 Spring 框架不会评估 JSP 或 EL 表达式