Can't create CSRF token with Spring Security

前端 未结 6 1317
清酒与你
清酒与你 2020-12-29 10:26

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

According to the documentation here, it should be possible to us

相关标签:
6条回答
  • 2020-12-29 10:54

    In case you don't need to use Thymeleaf, I'd suggest the following:

    1. Add this to the top of your page:

      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
      
    2. Add this to your login form:

      <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
      
    3. Add these dependencies to your pom.xml:

      <dependency>
          <groupId>org.apache.tomcat.embed</groupId>
          <artifactId>tomcat-embed-jasper</artifactId>
          <scope>provided</scope>
      </dependency>
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>jstl</artifactId>
      </dependency>   
      

    After struggling a lot, that worked for me.

    0 讨论(0)
  • 2020-12-29 10:59

    Before adding the thymeleaf-extras-springsecurity namespace and its dependency into my project, I had similar problems. I never did get the meta tags to work, even with thymeleaf-extras-springsecurity. But I did successfully retrieve Spring Security's csrf token using the hidden input. I have instructions below that work for me:
    In the html tag, add:
    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"

    In your pom.xml (if you're using Maven) you'll need to add the dependency: thymeleaf-extras-springsecurity4.
    Then add the hidden input inside your page's body to retrieve the csrf token.
    <input type="hidden" id= "csrf-token" th:name="${_csrf.parameterName}" th:content="${_csrf.token}" />
    and then use that within your javascript/jquery as follows:
    function f1() { var token1 = $('input#csrf-token').attr("content"); ... $.ajax({ ... type: "POST", beforeSend: function (request) { request.setRequestHeader("X-CSRF-TOKEN", token1); }, ...
    This all assumes that you have spring security enabled, and that you have NOT turned off csrf protection.

    0 讨论(0)
  • 2020-12-29 11:00

    I started with the same source article as you, I think, and the same "you should be able to" add answers as you did. I fought it a different way. I made Thymeleaf give me the answer I wanted.

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

    Thymeleaf put the attribute "content" with the requested Spring EL contents. I then used the provided JavaScript/JQuery to extract the info from the meta tags straight into the CSRF header.

    0 讨论(0)
  • 2020-12-29 11:02

    You have incorrect configuration for springSecurityFilterChain in your web.xml. Correct definition is:

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    

    Spring Security uses set of servlet filters to provide the functionality it is offering (including CSRF protection). These filters are defined as Spring beans (i.e. they are instantiated and managed by Spring application context). DelegatingFilterProxy is a special type of servlet filter, which finds root application context on the registered servlet context and delegates every call to the same named bean.

    0 讨论(0)
  • 2020-12-29 11:04

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

    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.

    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

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

    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.

    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.

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

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

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

    0 讨论(0)
  • 2020-12-29 11:12

    Your issue is a different one, just stumbled across this one as well and it took me several hours to figure out the cause. The cause for the issue described by you is that you did not enable csrf support within your spring-security.xml

    This little snippet needs to go into your security-config.xml:

    <!-- Static resources such as CSS and JS files are ignored by Spring Security -->
    <security:http pattern="/static/**" security="none" />
    
    <security:http use-expressions="true">
    
        <!-- Enables Spring Security CSRF protection -->
        <security:csrf/>
    
        <!-- Configures the form login -->
        <security:form-login
                login-page="/login"
                login-processing-url="/login/authenticate"
                authentication-failure-url="/login?error=bad_credentials"
                username-parameter="username"
                password-parameter="password"/>
        <!-- Configures the logout function -->
        <security:logout
                logout-url="/logout"
                logout-success-url="/login"
                delete-cookies="JESSIONID"/>
        <!-- Anyone can access these urls -->
        <security:intercept-url pattern="/auth/**" access="permitAll"/>
        <security:intercept-url pattern="/login" access="permitAll"/>
        <security:intercept-url pattern="/signin/**" access="permitAll"/>
        <security:intercept-url pattern="/signup/**" access="permitAll"/>
        <security:intercept-url pattern="/user/register/**" access="permitAll"/>
    
        <!-- The rest of our application is protected. -->
        <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
    
        <!-- Adds social authentication filter to the Spring Security filter chain. -->
        <security:custom-filter ref="socialAuthenticationFilter" before="PRE_AUTH_FILTER" />
    </security:http>
    ....
    ...
    ..
    .
    

    Save time by configuring this correctly...

    Cheerio, Flo!

    0 讨论(0)
提交回复
热议问题