2014-05-15 37 views
10

我在Spring MVC應用程序中使用了Spring Security 3.2.3,並且出現了一些意外的行爲。無法使用Spring Security創建CSRF令牌

按照documentation here,應該儘可能使用${_csrf.token}在我的HTML的meta標籤:

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

從我解壓的「內容」值使用JQuery,並將其放入請求頭使用AJAX。

由於某種原因,雖然Spring Security不會將其轉換爲實際的標記,但它只是作爲字符串「$ {_ csrf.token}」發送到標頭中。

根據文檔,嘗試使用${_csrf.token}作爲隱藏輸入的備用路徑,然後通過檢查輸入的值來試圖檢查令牌的計算結果,但它仍然只是純文本「$ {_ csrf.token}」 。

由於Spring Security似乎沒有生效,我是否缺少某種配置?我目前使用準系統春季安全Java配置(而不是XML)如下所示:

import org.springframework.context.annotation.*; 
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 
import org.springframework.security.config.annotation.web.configuration.*; 

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .csrf(); 
     } 
} 

我知道配置,因爲我把調試語句在它獲取調用,所以我認爲CSRF保護確實是因爲它應該是默認的。

我意識到語法「$ {}」是JSP表達式語言,和我目前成功地用它來評估方面與Thymeleaf的對象,例如:

th:object="${context}" 

所以我嘗試添加「日:」在meta標籤的「內容」的前面,像這樣:

<meta name="_csrf" th:content="${_csrf.token}"/> 

但它導致一個例外,這不能評價:

異常評估SpringEL的表情:「_csrf.token」

我認爲這裏的密鑰可以搞清楚如何得到表達我的觀點正確評價。

+1

是否有可能「$ {_ csrf.token}」語法只能在JSP中使用,而不能在.html文件中使用? – starmandeluxe

+0

現在的問題是,在運行Spring Security的時候,即使我們已經設置了認證方法,它也很煩人地想要認證用戶,所以我得到了未經授權的錯誤。我需要找出如何繞過Spring Security的默認認證要求...似乎沒有簡單的方法來關閉它,如果您不包含認證配置,整個應用程序拒絕運行(瘋狂!)。我只想從這個框架中獲得CSRF功能!將繼續調查如何繞過... – starmandeluxe

+1

所以經過反覆測試,似乎Spring Security運行,但我仍然只獲得$ {_ csrf.token}的字符串。當JSP需要評估值時,我認爲它與我使用.html文件有關,但將其更改爲.jsp文件會導致「org.thymeleaf.exceptions.TemplateInputException:解析模板{myapplication}時出錯,模板可能不存在或可能無法通過任何已配置的模板解析器訪問「 – starmandeluxe

回答

10

我終於解決了這個問題,但它基本上需要重寫Spring Security。這是它的全部榮耀。

首先,我遵循Eyal Lupu的博客文章here中的建議,但由於我的AJAX要求,我不得不根據自己的情況對它進行調整。

對於Thymeleaf情況,關鍵珍聞在Thymeleaf論壇的檔案隱藏起來 - 聲名狼藉的問題7.

https://github.com/thymeleaf/thymeleaf-spring/issues/7#issuecomment-27643488

通過Thymeleaf自己的創造者最後評論說:

th:action ...檢測時被一個 標籤,可呈現應該是唯一的地方應用這個屬性,anyway--,在這種情況下 調用RequestDataValueProcessor.getExtraHiddenFields(...)並在結束標記之前添加返回的隱藏字段 。

這是我需要讓令牌工作的關鍵短語。不幸的是,它爲什麼th:action也會啓動getExtraHiddenFields並不是很明顯,但無論如何它確實如此,這就是最重要的。

因此,對於任何人Thymeleaf + Spring Security的CSRF + AJAX POST掙扎,這裏有我的腳步(這是削下來不少,但這些都是高層次的概念來解決它):

  1. 實現Spring接口RequestDataValueProcessor並將其註冊到Spring Security的XML配置中,以便您可以重寫getExtraHiddenFields方法,該方法允許您將隱藏的輸入字段插入HTML(當然帶有令牌)。令牌本身是使用Java.Util UUID生成的。

  2. 使用JQuery,從該隱藏字段中讀取值並設置Request Header的「X-CSRF-Token」屬性,以便通過HTTP發送該屬性。無法簡單地將令牌留在隱藏的輸入字段中,因爲我們沒有進行表單提交,而是使用AJAX POST來調用服務器端的方法。

  3. 擴展Spring的HandlerInterceptorAdapter,並將其註冊爲攔截器,以便每次POST方法完成時,調用服務器端的「preHandle」方法,以便它可以比較請求標記(從HTTP標頭中提取上一步)到會話的令牌(應該是相同的!)。檢查完成後,它可以允許請求通過或返回錯誤。

1

您的web.xml中的springSecurityFilterChain配置錯誤。正確的定義是:

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

Spring Security使用Servlet過濾器的設置,以提供它是提供(包括CSRF保護)功能。這些過濾器被定義爲Spring bean(即它們被Spring應用程序上下文實例化和管理)。 DelegatingFilterProxy是一種特殊類型的servlet過濾器,它在註冊的servlet上下文上找到根應用上下文,並將每個調用委託給同一個命名的bean。

+0

謝謝。但是,它對行爲沒有影響。仍然只是看到一個字符串爲csrf令牌:( – starmandeluxe

+0

這裏有一個問題:如果我的配置文件是一個Java類,但其他配置是在web.xml中完成嗎?是否有必要只有所有-XML配置,還是隻有全Java配置? – starmandeluxe

+0

您可以根據需要混合使用XML和Java配置。當然你需要仔細觀察誰在加載什麼。如果嘗試將名稱空間配置('')與特殊的註釋配置('@ EnableWebMvcSecurity')混合,可能會出現問題。 –

3

我開始使用與您相同的source article,我認爲您的答案和「您應該能夠」相同。我以一種不同的方式去戰鬥。我讓Thymeleaf給我我想要的答案。

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

Thymeleaf將屬性「content」與請求的Spring EL內容放在一起。然後,我使用提供的JavaScript/JQuery將元標記中的信息直接提取到CSRF頭中。

0

你的問題是一個不同的,只是偶然發現了這一個,以及和我花了幾個小時,以找出原因。通過您所描述的問題的原因是你沒有你的彈簧security.xml文件

這個小片段需要進入安全-config.xml文件中啓用CSRF支持:

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

保存通過正確配置此時間...

Cheerio, Flo!

3

在將thymeleaf-extras-springsecurity命名空間及其依賴項添加到我的項目之前,我遇到了類似的問題。我從來沒有使用meta標籤工作,即使是用thymeleaf-extras-springsecurity。但我確實使用隱藏的輸入成功檢索了Spring Security的csrf標記。我有下面的工作指示我:
HTML標記,添加:
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"

在你的pom.xml(如果你使用Maven),你需要添加依賴性:thymeleaf- extras-springsecurity4
然後在頁面正文中添加隱藏的輸入以檢索csrf標記。
<input type="hidden" id= "csrf-token" th:name="${_csrf.parameterName}" th:content="${_csrf.token}" />
,然後使用你的JavaScript/jQuery的範圍內:
function f1() { var token1 = $('input#csrf-token').attr("content"); ... $.ajax({ ... type: "POST", beforeSend: function (request) { request.setRequestHeader("X-CSRF-TOKEN", token1); }, ...
這一切都假定您啓用了春天的安全性,並且您還沒有關閉CSRF保護。

+0

沒有爲我工作。 –

0

如果你不需要使用Thymeleaf,我建議如下:

  1. 添加到您的頁面的頂部:

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 
    
  2. 添加到您的登錄表單:

    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> 
    
  3. 這些依賴添加到你的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> 
    

掙扎了很多,這對我的工作後。