在请求参数'_csrf'或标头'X-CSRF-TOKEN'上发现无效的CSRF令牌'null'


90

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

这是spring安全配置:

<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>

login.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'.

更新 在进行一些调试之后,请求对象会脱离DelegatingFilterProxy的形式,但是在CoyoteAdapter的第469行中,它执行request.recycle();。删除所有属性...

我在JDK 1.7的Tomcat 6.0.36、7.0.50中进行了测试。

我还不了解这种行为,相反,如果有人指出我对与CSRF一起使用的Spring Security 3.2进行一些应用程序示例战争的方向是可能的。


1
您使用什么春季版本?对于spring-security.xmlSpring 4.0.0 RELEASE(GA),Spring Security 3.2.0 RELEASE(GA)(尽管它与Struts 2.3.16集成在一起),这件事对我也有效(但是存在差异)。尝试单独使用Spring MVC)。但是,当请求多部分地上传状态为403的文件时,它失败了。我正在努力寻找解决方案。
2014年

Spring 3.2.6,Spring Security 3.2.0,CSRF,令牌已添加到http-request对象中,会话对象与请求线程相同,但是出去之前,直到其呈现jsp时,删除所有属性并且仅留下一个属性... filter_applied
雨果·罗巴

@Tiny:您是否找到解决多部分问题的解决方案?我有完全一样的问题。
罗伯·约翰森

1
@AlienBishop:是的,请查看答案(它结合使用Spring和Struts)。如果您只有Spring MVC,请查看答案。应该注意的是,过滤器的顺序web.xml至关重要。MultipartFilter必须在之前声明springSecurityFilterChain。希望能有所帮助。谢谢。
2014年

Answers:


110

看起来您的Spring应用程序中的CSRF(跨站点请求伪造)保护已启用。实际上,默认情况下它是启用的。

根据spring.io

什么时候应该使用CSRF保护?我们的建议是对普通用户可能由浏览器处理的任何请求使用CSRF保护。如果仅创建非浏览器客户端使用的服务,则可能需要禁用CSRF保护。

所以要禁用它:

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

如果您想使CSRF保护保持启用状态,则必须在表格中添加csrftoken。您可以这样做:

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

您甚至可以在表单的操作中包含CSRF令牌:

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

2
应该接受此答案,因为它不仅说明了做什么,而且还说明了在采取措施阻止这些错误之前应该考虑的事项。
Thomas Carlisle

1
您也可以.csrf().ignoringAntMatchers("/h2-console/**")
insan-e

在上面的答案中避免通过查询参数样式。如果这样做,则是公开公开令牌。
Pramod S. Nikam

31

您不应该添加到登录表单吗?

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

如Spring安全性文档中的此处所述


12

如果您将应用,security="none"则不会生成任何csrf令牌。该页面不会通过安全过滤器。使用角色匿名。

我没有详细介绍,但是它对我有用。

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

我使用的是security = none,然后转到您的答案即可解决此问题。很棒的thymeleaf会自动添加csrf令牌。谢谢 !
rxx

7

尝试将以下内容更改<csrf /> 为:<csrf disabled="true"/>。它应该禁用csfr。


7

使用百里香叶,您可以添加:

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

6

禁用CSRF的Spring文档: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();
   }
}

请不要复制现有答案。
james.garriss

4

我曾经有过同样的问题。

您的配置使用security =“ none”,因此无法生成_csrf:

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

您可以为/login.jsp页面设置access =“ IS_AUTHENTICATED_ANONYMOUSLY”替换上面的配置:

<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>


1

在Github上查看我的工作示例应用程序,并将其与您的设置进行比较。


我将降级到Spring 3.2.6,我希望它在没有Spring MVC的情况下也可以工作。
Hugo Robayo 2014年

是的,当我从Spring 3.1.4的现有应用程序中创建示例应用程序时,它应该可以正常工作。
manish 2014年

哈哈哈哈哈哈哈哈哈,太棒了,要让它仅降级就不能解决bhaiya ji @manish
Kuldeep Singh

1

没有一种解决方案对我有用。以Spring形式为我工作的唯一一个是:

action =“ ./ upload?$ {_ csrf.parameterName} = $ {_ csrf.token}”

替换为:

action =“ ./ upload?_csrf = $ {__ csrf.token}”

(Spring 5在Java配置中启用了CSRF)


0

在您的控制器中添加以下内容:

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

并在jsp页面上添加

<form:form modelAttribute="someName" action="someURI?${_csrf.parameterName}=${_csrf.token}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.