简体   繁体   中英

SPRING CSRF throws 405 despite CSRF token in request

I have a web application that works when I put <security:csrf disabled="true"/> in my security config, but doesn't work when I enable it. I conclude therefore than I'm an idiot, but can't figure out why.

The symptoms are:

  • Throws 405 when deployed in Tomcat with <security:csrf/>
  • Works in Tomcat with <security:csrf disabled="true"/>
  • Works when run under STS's Pivotal server, even with <security:csrf/>

The precise error is:

"POST /works-1.0-SNAPSHOT/auth/register HTTP/1.1" 405 1088

Here is my registration form:

<%@ page import="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Register</title>
    </head>
    <body>

        <h1>Register</h1>
        <div class="error">${error}</div>
        <c:url var="post_url" value="/auth/register"/>
        <form action="${post_url}" method="post" >
      <p>
        <label for="j_username">Login:</label>
        <input id="j_username" name="j_username" type="text" value="${j_username}"/>
      </p>
      <p>
        <label for="j_displayname">Name:</label>
        <input id="j_displayname" name="j_displayname" type="text" value="${j_displayname}"/>
      </p>
      <p>
        <label for="j_password">Password:</label>
        <input id="j_password" name="j_password" type="password" />
      </p>
       <input type="hidden" name="${_csrf.parameterName}"
                        value="${_csrf.token}" />
      <input  type="submit" value="Register"/>
    </form>
    <br/>
    <a href="/auth/login">Login</a>
    </body>
</html>

(If you think that this form looks suspiciously like SDN4-cineasts 's one, you're right: my project is derived from that source code.)

As you can see, the CSRF token is in there. When I "show source" on the displayed web page, I can see that the token is indeed present. Any ideas?

Here is my pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.artdecode.works</groupId>
    <artifactId>works</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>Works database</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- <spring.version>4.2.4.RELEASE</spring.version> -->
        <spring.version>4.3.2.RELEASE</spring.version>
        <spring.commons.version>1.12.0.BUILD-SNAPSHOT</spring.commons.version>
        <!-- <spring.security.version>4.0.3.RELEASE</spring.security.version> -->
        <spring.security.version>4.1.3.RELEASE</spring.security.version>
        <!-- <neo4j.version>2.3.2</neo4j.version>  -->
        <neo4j.version>3.0.3</neo4j.version>
        <!-- <sdn.version>4.1.0.M1</sdn.version> -->
        <sdn.version>4.1.2.RELEASE</sdn.version>
        <neo4j.ogm.version>2.0.4</neo4j.ogm.version>
    </properties>

    <dependencies>
        <!-- J2EE -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>


       <!-- Spring -->

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j</artifactId>
            <version>${sdn.version}</version>
        </dependency>

        <dependency>
            <groupId>opensymphony</groupId>
            <artifactId>sitemesh</artifactId>
            <version>2.4.2</version>
        </dependency>

        <!-- Neo4j -->
        <dependency>
            <groupId>org.neo4j.app</groupId>
            <artifactId>neo4j-server</artifactId>
            <version>${neo4j.version}</version>
        </dependency>
        <!-- 
        <dependency>
          <groupId>org.neo4j</groupId>
          <artifactId>neo4j-ogm-bolt-driver</artifactId>
          <version>2.0.4</version>
        </dependency>
        -->

        <!-- Tests -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-ogm-test</artifactId>
            <version>${neo4j.ogm.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.neo4j.test</groupId>
            <artifactId>neo4j-harness</artifactId>
            <version>${neo4j.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-library</artifactId>
            <version>1.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j</artifactId>
            <version>${sdn.version}</version>
            <type>test-jar</type>
        </dependency>

        <!-- Others -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.21</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
        </dependency>

    </dependencies>


    <repositories>
        <repository>
            <id>spring-libs-snapshot</id>
            <name>Spring</name>
            <url>http://repo.spring.io/libs-snapshot</url>
        </repository>

        <repository>
            <id>spring-snapshots</id>
            <url>http://repo.spring.io/snapshot</url>
            <snapshots><enabled>true</enabled></snapshots>
        </repository>

        <repository>
            <id>spring-milestones</id>
            <url>http://repo.spring.io/milestone</url>
        </repository>

        <repository>
            <id>neo4j</id>
            <url>http://m2.neo4j.org/content/repositories/releases</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>

    </repositories>
    <pluginRepositories>

        <pluginRepository>
            <id>spring-snapshots</id>
            <url>http://repo.spring.io/snapshot</url>
        </pluginRepository>

        <pluginRepository>
            <id>spring-milestones</id>
            <url>http://repo.spring.io/milestone</url>
        </pluginRepository>

</pluginRepositories>



    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>7.6.5.v20120716</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <stopKey>foo</stopKey>
                    <stopPort>9999</stopPort>
                    <jvmArgs></jvmArgs>
                    <systemProperties>
                        <systemProperty>
                            <name>username</name>
                            <value>neo4j</value>
                        </systemProperty>
                        <systemProperty>
                            <name>password</name>
                            <value>neo</value>
                        </systemProperty>
                    </systemProperties>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Here is my web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

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

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
    <listener-class>
        org.springframework.web.context.request.RequestContextListener
    </listener-class>
    </listener>
    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>
            com.opensymphony.module.sitemesh.filter.PageFilter
        </filter-class>
    </filter>

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

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <session-config>
      <session-timeout>60</session-timeout>
    </session-config>
</web-app>

Here is my security configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <context:annotation-config/>
    <security:global-method-security secured-annotations="enabled">
    </security:global-method-security>

    <security:http> <!-- use-expressions="true" -->
        <security:intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')"/>
        <security:intercept-url pattern="/import/*" access="hasRole('ROLE_ADMIN')"/>
        <security:intercept-url pattern="/user/**" access="hasRole('ROLE_USER')"/>
        <security:intercept-url pattern="/auth/login" access="isAnonymous()"/>
        <security:intercept-url pattern="/auth/register" access="isAnonymous()"/>
        <security:intercept-url pattern="/resources/**" access="permitAll"/>
        <security:intercept-url pattern="/images/**" access="permitAll"/>
        <security:intercept-url pattern="/**" access="isAnonymous() || hasRole('ROLE_USER')"/>
        <security:form-login login-page="/auth/login"
            authentication-failure-url="/auth/login?login_error=true"
            default-target-url="/user"
            login-processing-url="/j_spring_security_check"
            username-parameter="username"
            password-parameter="password"/>
        <security:logout logout-success-url="/" invalidate-session="true" logout-url="/j_spring_security_logout"/>
        <security:access-denied-handler error-page="/auth/denied" />
        <security:csrf/>
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userRepository">
            <security:password-encoder hash="md5">
                <security:salt-source system-wide="cewuiqwzie"/>
            </security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>

</beans>

Problem solved: I had cookies disabled in my browser. It was not a problem with either Tomcat or my code, it was a problem with my browser.

Could someone at Spring please make it possible to distinguish between "Invalid CSRF token found" and "Expected token is empty (probably cookie not set)"?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM