Spring Security (3.2.5) HTTP POST does not forward original request after authentication

I have a sample Spring MVC application protected by Spring security (Spring version 4.0.1.RELEASE, Spring security 3.2.5.RELEASE. When I send an HTTP GET request as an unauthenticated user, I am sent to the login page (like expected) where, after being authenticated, I go to the page requested in the original GET.

When I submit an HTTP POST request as an unauthenticated user, I am sent to the login page (as expected), but upon successful authentication, I am sent to the page as specified in my "default target url" page specified in my the initial POST request.

When I try to use the same HTTP POST protocol as an authenticated user, it works just fine (as expected). I've already tried setting always-use-default-target = "false" and also excluding this property entirely and the behavior is the same.

Am I missing something? Does Spring have to go through a POST request after authentication or is it somehow not happening by design?

Here is my Spring Security Configuration:

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

    <http auto-config="true">
        <intercept-url pattern="/admin/**" access="ROLE_USER" />
        <form-login 
            login-page="/login.htm" 
            default-target-url="/hello.htm" 
            always-use-default-target="false"
            authentication-failure-url="/login.htm?error" 
            username-parameter="username"
            password-parameter="password" />
        <logout logout-success-url="/login.htm?logout" />
        <!-- enable csrf protection -->
        <csrf/>
    </http>

    <authentication-manager>
      <authentication-provider>
        <user-service>
        <user name="admin" password="password" authorities="ROLE_USER" />
        <user name="super" password="man" authorities="ROLE_SUPER_USER" />
        </user-service>
      </authentication-provider>
    </authentication-manager>

</beans:beans>

      

Here is my jsp for running the test (link for GET testing and POST validation forms):

<%@ include file="/WEB-INF/jsp/include.jsp" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<html>
  <head><title>TEST SECURITY</title></head>
  <body>
        <p><a href="admin/security_landing.htm">GET</a></p>
        <form:form  method="POST" action="admin/security_landing.htm"><input type="submit" value="POST"></form:form>

  </body>
</html>

      

Here is the landing page, which is a protected resource:

<%@ include file="/WEB-INF/jsp/include.jsp" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<html>
  <head><title>TEST SECURITY LANDING PAGE</title></head>
  <body>
        <p>YOU MADE IT!!!!</p>
  </body>
</html>

      

and here is my test controller:

package springapp.web;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


@Controller
public class TestController {

    /** Logger for this class and subclasses */
    protected final Log logger = LogFactory.getLog(getClass());

    @RequestMapping(value="test", method= RequestMethod.GET)
    public ModelAndView methodGet()
            {

        logger.info("Found it way to the GET method");

        ModelAndView model = new ModelAndView();

        model.setViewName("security_test");

        return model;

    }

    @RequestMapping(value="/admin/security_landing", method=RequestMethod.POST)
    public ModelAndView sendToLandingPOST()
            {

        logger.info("Found it way to the GET method");

        ModelAndView model = new ModelAndView();

        model.setViewName("/admin/security_landing");

        return model;

    }

    @RequestMapping(value="/admin/security_landing", method= RequestMethod.GET)
    public ModelAndView sendToLandingGET()
            {

        logger.info("Found it way to the GET method");

        ModelAndView model = new ModelAndView();

        model.setViewName("/admin/security_landing");

        return model;

    }
}

      

I can include more Spring configuration if appropriate, but where the application is working fine with GET but not working properly (in my opinion) with POST, I think it is isolated from the parts I am shown here.

It seems to me that Spring security should be able to intercept POST and go through POST after authentication like GET.

Any hints or help would be appreciated. Thanks, Rob

+3


source to share


1 answer


As stated, when CSRF is enabled Spring Security will only save GET requests. The reason is that the CSRF token changes as soon as the user authenticates to prevent a malicious user from discovering the CSRF before the user authenticates (that is, in a public setting). If we have cached the request then it will be renamed with the old CSRF and will not be confirmed by the CSRF anyway.

All in all, saving the POST request and processing it automatically seems a little dangerous. Consider a situation where a public computer contains access to a commonly used site. The attacker performs a POST on an unauthenticated application that transfers funds from the current authenticated user to his bank account. The application caches the POST and then displays the registration form. The attacker leaves, and the victim sees that the login page is already present. Also, the URL in the browser renders correctly and over HTTPS. The victim is registered and the originally requested POST request is played back and automatically transfers funds from the victim to the attacker.



Instead, we should probably make sure that the intermediate page is rendered when replaying the POST.

+2


source







All Articles