2014-11-05 36 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重播時顯示中間頁面。