2014-11-05 100 views
3

我有一个Spring安全示例Spring Spring MVC应用程序(Spring version 4.0.1.RELEASE,Spring security 3.2.5.RELEASE。我发送一个HTTP GET请求作为一个未经身份验证的用户,我发送到登录页面(如预期),在我验证身份后,我将发送到原始GET请求的页面Spring Security(3.2.5)HTTP POST在验证后不会转发到原始请求

当我发送HTTP POST请求作为一个未经身份验证的用户,我发送到登录页面(按预期),但成功身份验证后,我发送到我的“default-target-url”中指定的页面,而不是我的原始请求中的页面POST请求。

当我尝试使用与已认证的用户相同的HTTP POST时,它工作得很好(如预期的那样)。我已经尝试设置always-use-default-target =“false”,并且完全省略该属性并且行为相同。

我错过了什么吗? Spring是否应该在身份验证之后传递POST请求,或者由于某种原因而不按设计发生?

这里是我的春节,安全配置:

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

这里是我的jsp发起测试(链路测试GET和测试POST形式):

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

这里是着陆页,这是一个安全资源:

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

这里是我的测试控制器:

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's 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's 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's way to the GET method"); 

     ModelAndView model = new ModelAndView(); 

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

     return model; 

    } 
} 

我可以加入更多的Spring配置,如果是相关的,但其中的应用程序工作正常使用GET,但行为不端的(在我看来)有一个帖子,我想这是隔离件我这里已经展示了。

在我看来,Spring安全应该能够拦截一个POST并在身份验证后传递POST,就像GET一样。

任何提示或帮助,将不胜感激。 谢谢, Rob

+0

通过试验,我已经隔离了这个问题,以启用CSRF保护的存在。当标签出现在安全配置中时,会发生此问题。当它被删除时,应用程序按预期工作。不知道为什么,但至少我已经隔离了原因。 – 2014-11-05 20:53:27

+0

如果您正在使用CSRF检查,那么您需要在表单提交中提交CSRF令牌。 [手册]中有一个例子(http://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/reference/htmlsingle/#csrf-using)。 – 2014-11-07 15:29:36

+0

感谢卢克,我实际上使用了form form:form标签,它应该自动处理CSRF标签,但我也试过显式包含token。没有运气。我在文档中发现了这一点,这让我相信这种行为可能是设计的。 – 2014-11-10 14:38:34

回答

2

正如指出的那样,当CSRF启用时,Spring Security将只保存GET请求。原因是一旦用户认证,CSRF令牌就会发生变化,以防止恶意用户在用户认证之前(即在公开场合)发现CSRF。如果我们缓存了请求,那么它将与旧的CSRF一起重播并无法通过CSRF验证。

通常,保存POST请求并自动处理它似乎有点危险。考虑一下公共计算机可以访问常用网站的情况。恶意用户对未经身份验证的应用程序执行POST,该应用程序将资金从当前通过身份验证的用户转移到他们的银行账户。应用程序缓存POST,然后调出登录表单。恶意用户走开,受害者看到登录页面已经存在。此外,浏览器中的URL通过HTTPS正确显示。受害者登录并重播最初请求的POST请求,并自动将资金从受害者转移给恶意用户。

相反,我们应该确保在POST重播时显示中间页面。