在请求参数‘_CSRF’或头部‘ X-CSRF-TOKEN’上发现无效的 CSRF 令牌‘ null’

在配置 Spring Security 3.2之后,_csrf.token不绑定到请求或会话对象。

这是弹簧安全配置:

<http pattern="/login.jsp" security="none"/>


<http>
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login login-page="/login.jsp"
authentication-failure-url="/login.jsp?error=1"
default-target-url="/index.jsp"/>
<logout/>
<csrf />
</http>


<authentication-manager>
<authentication-provider>
<user-service>
<user name="test" password="test" authorities="ROLE_USER/>
</user-service>
</authentication-provider>
</authentication-manager>

Jsp 文件

<form name="f" action="${contextPath}/j_spring_security_check" method="post" >
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<button id="ingresarButton"
name="submit"
type="submit"
class="right"
style="margin-right: 10px;">Ingresar</button>
<span>
<label for="usuario">Usuario :</label>
<input type="text" name="j_username" id="u" class="" value=''/>
</span>
<span>
<label for="clave">Contrase&ntilde;a :</label>


<input type="password"
name="j_password"
id="p"
class=""
onfocus="vc_psfocus = 1;"
value="">
</span>
</form>

它呈现下一个 html:

<input type="hidden" name="" value="" />

结果是403 HTTP 状态:

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

更新 经过一些调试之后,request 对象会从 RegiatingFilterProxy 中出来,但是在 CoyoteAdapter 的第469行中,它会执行 request.loop () ; 这会删除所有的属性..。

我使用 JDK 1.7在 Tomcat 6.0.36、7.0.50中进行测试。

我还没有理解这种行为,相反,如果有人给我指出某个应用程序示例与 Spring Security 3.2之间的战争的方向,这是可能的,这个应用程序示例与 CSRF 一起工作。

159706 次浏览

Please see my working sample application on Github and compare with your set up.

Shouldn't you add to the login form?;

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

As stated in the here in the Spring security documentation

i think csrf only works with spring forms

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

change to form:form tag and see it that works.

It looks like the CSRF (Cross Site Request Forgery) protection in your Spring application is enabled. Actually it is enabled by default.

According to spring.io:

When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.

So to disable it:

@Configuration
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}

If you want though to keep CSRF protection enabled then you have to include in your form the csrftoken. You can do it like this:

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

You can even include the CSRF token in the form's action:

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">

Try to change this: <csrf /> to this : <csrf disabled="true"/>. It should disable csfr.

If you will apply security="none" then no csrf token will be generated. The page will not pass through security filter. Use role ANONYMOUS.

I have not gone in details, but it is working for me.

 <http auto-config="true" use-expressions="true">
<intercept-url pattern="/login.jsp" access="hasRole('ANONYMOUS')" />
<!-- you configuration -->
</http>

I used to have the same problem.

Your config use security="none" so cannot generate _csrf:

<http pattern="/login.jsp" security="none"/>

you can set access="IS_AUTHENTICATED_ANONYMOUSLY" for page /login.jsp replace above config:

<http>
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login login-page="/login.jsp"
authentication-failure-url="/login.jsp?error=1"
default-target-url="/index.jsp"/>
<logout/>
<csrf />
</http>

With thymeleaf you may add:

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

Spring documentation to disable csrf: https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-configure

@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {


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

In your controller add the following:

@RequestParam(value = "_csrf", required = false) String csrf

And on jsp page add

<form:form modelAttribute="someName" action="someURI?${_csrf.parameterName}=${_csrf.token}

Neither one of the solutions worked form me. The only one that worked for me in Spring form is:

action="./upload?${_csrf.parameterName}=${_csrf.token}"

REPLACED WITH:

action="./upload?_csrf=${_csrf.token}"

(Spring 5 with enabled csrf in java configuration)