13. The Security Filter Chain(安全过滤链)
Spring Security的網絡基礎設施完全基于標準的servlet過濾器。它在內部不使用servlet或任何其他基于servlet的框架(如Spring MVC),因此它與任何特定的web技術都沒有強有力的鏈接。它處理HttpServletRequest和HttpServletResponse,不關心請求是來自瀏覽器、網絡服務客戶端、HttpInvoker還是AJAX應用程序。
Spring Security在內部維護一個過濾器鏈,其中每個過濾器都有特定的職責,并且根據需要的服務從配置中添加或刪除過濾器。過濾器的排序很重要,因為它們之間存在依賴關系。如果您一直在使用命名空間配置,那么過濾器會自動為您配置,并且您不必顯式定義任何Spring beans,但是有時您可能希望完全控制安全過濾器鏈,這可能是因為您正在使用命名空間中不支持的功能,或者您正在使用您自己定制的類版本。
13.1 DelegatingFilterProxy(委托過濾器代理)
當使用servlet過濾器時,您顯然需要在您的web.xml中聲明它們,否則它們將被servlet容器忽略。在Spring Security中,過濾器類也是在應用程序上下文中定義的Spring beans,因此能夠利用Spring豐富的依賴注入工具和生命周期接口。Spring的DelegatingFilterProxy提供了web.xml和應用程序上下文之間的鏈接。
當使用DelegatingFilterProxy時,您將在web.xml文件中看到類似的內容:
請注意,過濾器實際上是一個DelegatingFilterProxy,而不是實際實現過濾器邏輯的類。DelegatingFilterProxy所做的是將過濾器的方法委托給一個從Spring應用程序上下文中獲得的bean。這使bean能夠受益于Spring web應用程序上下文生命周期支持和配置靈活性。該bean必須實現javax.servlet.Filter,并且必須與filter-name元素中的名稱相同。有關更多信息,請閱讀用于DelegatingFilterProxy的Javadoc
13.2 FilterChainProxy(過濾器鏈代理)
Spring Security的web基礎結構只能通過委托給FilterChainProxy的實例來使用。安全過濾器不應單獨使用。理論上,您可以在應用程序上下文文件中聲明您需要的每個Spring Security過濾器bean,并為每個過濾器向web.xml添加一個相應的DelegatingFilterProxy條目,確保它們的順序正確,但是如果有很多過濾器,這將很麻煩,并且會很快使web.xml文件混亂。FilterChainProxy允許我們向web.xml添加一個條目,并完全處理應用程序上下文文件來管理我們的web安全beans。它使用一個DelegatingFilterProxy進行連接,就像上面的例子一樣,但是過濾器名稱被設置為bean名稱“filterChainProxy”。然后在應用程序上下文中用相同的bean名稱聲明過濾器鏈。這里有一個例子:
命名空間元素filter-chain用于方便地設置應用程序中所需的安全過濾器鏈。它將一個特定的URL模式映射到一個由filters元素中指定的bean名稱構建的篩選器列表,并將它們組合到一個SecurityFilterChain類型的bean中。模式屬性采用ant路徑,最具體的URIs應該首先出現,在運行時,FilterChainProxy將定位與當前網絡請求匹配的第一個URI模式,并且由過濾器屬性指定的過濾器beans列表將應用于該請求。過濾器將按照它們被定義的順序被調用,因此您可以完全控制應用于特定網址的過濾器鏈。
您可能已經注意到我們在篩選器鏈中聲明了兩個securitycontextPersistenceFilter(ASC是allowSessionCreation的縮寫,是securitycontextPersistenceFilter的一個屬性)。因為web服務永遠不會在將來的請求中提供jsessionid,所以為這樣的用戶代理創建HttpSession是一種浪費。如果您有一個需要最大可伸縮性的大容量應用程序,我們建議您使用上面顯示的方法。對于較小的應用,使用單個securityContextPersistenceFilter(其默認的allowSessionCreation為true)可能就足夠了。
請注意,FilterChainProxy不會在其配置的過濾器上調用標準過濾器生命周期方法。我們建議您使用Spring的應用程序上下文生命周期接口作為替代,就像您使用任何其他Spring bean一樣。
當我們研究如何使用命名空間配置來設置網絡安全時,我們使用了一個名為“springSecurityFilterChain”的DelegatingFilterProxy。您現在應該能夠看到這是由命名空間創建的FilterChainProxy的名稱。
13.2.1 Bypassing the Filter Chain(旁路過濾器鏈)
您可以使用屬性過濾器=“none”作為提供過濾器bean列表的替代方法。這將從安全過濾器鏈中完全省略請求模式。請注意,匹配此路徑的任何內容都不會應用任何身份驗證或授權服務,并且可以自由訪問。如果您想在請求期間使用安全上下文的內容,那么它必須已經通過了安全過濾器鏈。否則,SecurityContextHolder將不會被填充,并且內容將為空。
13.3 Filter Ordering(過濾器排序)
過濾器在鏈中的定義順序非常重要。不管您實際使用的是哪種過濾器,順序都應該如下:
通道處理過濾器(ChannelProcessingFilter),因為它可能需要重定向到不同的協議。
securitycontextPersistenceFilter,這樣就可以在web請求開始時在SecurityContextHolder中設置一個SecurityContext,并且當web請求結束時,對SecurityContext的任何更改都可以復制到HttpSession中(準備用于下一個web請求)。
ConcurrentSessionFilter,因為它使用SecurityContextHolder功能,并且需要更新會話注冊以反映主體的持續請求。
身份驗證處理機制(Authentication processing mechanisms)-用戶名密碼身份驗證過濾器(UsernamePasswordAuthenticationFilter)、身份驗證過濾器(CasAuthenticationFilter)、基本身份驗證過濾器(BasicAuthenticationFilter)等-以便可以修改安全上下文持有者(SecurityContextHolder)以包含有效的身份驗證請求令牌。
securitycontextholderAreRequestFilter,如果您正在使用它在您的servlet容器中安裝一個支持Spring安全性的HttpServletRequestWrapper。
JaasApiIntegrationFilter,如果JaasAuthenticationToken在SecurityContextHolder中,這將把FilterChain作為JaasAuthenticationToken中的主題進行處理。
RememberMeAuthenticationFilter,如果沒有更早的身份驗證處理機制更新了SecurityContextHolder,并且請求提供了一個cookie,使得remember-me的服務能夠發生,那么合適的記住的身份驗證對象將被放在那里。
異常轉換過濾器(ExceptionTranslationFilter),捕獲任何Spring安全異常,以便返回一個HTTP錯誤響應或啟動一個適當的AuthenticationEntryPoint。
過濾器安全接口(FilterSecurityInterceptor),用于保護網絡URIs,并在訪問被拒絕時引發異常。
13.4 Request Matching and HttpFirewall(請求匹配和HttpFirewall)
Spring Security有幾個方面,您定義的模式會根據傳入的請求進行測試,以便決定應該如何處理請求。當FilterChainProxy決定一個請求應該通過哪個過濾器鏈時,以及當FilterSecurityInterceptor決定哪個安全約束應用于一個請求時,就會發生這種情況。根據您定義的模式進行測試時,了解機制是什么以及使用什么URL值是很重要的。
Servlet規范為HttpServletRequest定義了幾個屬性,這些屬性可以通過getter方法來訪問,我們可能希望與之匹配。這些是contextPath、servletPath、pathInfo和queryString。Spring Security只對保護應用程序中的路徑感興趣,因此忽略了上下文路徑。不幸的是,servlet規范沒有明確定義servletPath和pathInfo的值對于特定的請求URI將包含什么。例如,如RFC 2396 [8]中所定義的,一個網址的每個路徑段可以包含參數。規范沒有明確說明這些是否應該包含在servletPath和pathInfo值中,不同的servlet容器之間的行為也不同。當應用程序部署在沒有從這些值中剝離路徑參數的容器中時,存在一種危險,攻擊者可能會將它們添加到請求的URL中,以導致模式匹配意外成功或失敗。傳入網址的其他變化也是可能的。例如,它可以包含路徑遍歷序列(如/../)或多個正斜杠(//),這也可能導致模式匹配失敗。一些容器在執行servlet映射之前將它們規范化,但是其他的沒有。為了防止類似這樣的問題,FilterChainProxy使用HttpFirewall策略來檢查和包裝請求。默認情況下,未規范化的請求會被自動拒絕,并且出于匹配目的,路徑參數和重復斜線會被刪除。因此,使用過濾器鏈代理來管理安全過濾器鏈是非常重要的。請注意,servletPath和pathInfo值是由容器解碼的,因此您的應用程序不應該有任何包含分號的有效路徑,因為這些部分將被刪除以進行匹配。
如上所述,默認策略是使用Ant風格的路徑進行匹配,這可能是大多數用戶的最佳選擇。該策略在類AntPathRequestMatcher中實現,該類使用Spring的AntPathMatcher對連接的servletPath和pathInfo執行不區分大小寫的模式匹配,忽略查詢字符串。
如果出于某種原因,您需要更強大的匹配策略,您可以使用正則表達式。然后,策略實現是RegexRequestMatcher。有關更多信息,請參見該類的Javadoc。
在實踐中,我們建議您在服務層使用方法安全性來控制對應用程序的訪問,并且不要完全依賴于使用在web應用程序級別定義的安全性約束。網址會發生變化,很難考慮應用程序可能支持的所有可能的網址以及如何處理請求。你應該試著限制自己使用一些簡單易懂的ant路徑。始終嘗試使用“deny-by-default”方法,在該方法中,您最后定義了一個總括通配符(/或)并拒絕訪問。
在服務層定義的安全性更健壯,更難繞過,所以您應該總是利用Spring Security的方法安全性選項。
HTTP防火墻還通過拒絕HTTP響應頭中的換行字符來防止HTTP響應拆分。
認情況下,使用StrictHttpFirewall。該實現拒絕看似惡意的請求。如果它對你的需求來說太嚴格,那么你可以定制什么類型的請求被拒絕。然而,重要的是你要知道這可能會使你的應用程序受到攻擊。例如,如果您希望利用Spring MVC的矩陣變量,可以在XML中使用以下配置:
同樣的事情也可以通過Java配置來實現,方法是公開一個StrictHttpFirewall bean。
13.5 Use with other Filter-Based Frameworks(與其他基于過濾器的框架一起使用)
如果您正在使用其他一些基于過濾器的框架,那么您需要確保首先使用Spring Security過濾器。這使得SecurityContextHolder能夠被及時填充,以供其他過濾器使用。例子是使用SiteMesh來裝飾你的網頁或者像Wicket這樣的網絡框架,它使用過濾器來處理它的請求。
13.6 Advanced Namespace Configuration(高級命名空間配置)
正如我們在前面的命名空間章節中看到的,可以使用多個http元素為不同的URL模式定義不同的安全配置。每個元素在內部過濾器鏈代理中創建一個過濾器鏈,以及應該映射到它的網址模式。元素將按照它們被聲明的順序被添加,所以最具體的模式必須首先被聲明。這是另一個例子,類似于上面的情況,應用程序既支持無狀態RESTful API,也支持用戶使用表單登錄的普通web應用程序。
請注意,為了使用這種語法,您需要在應用程序上下文XML文件中包含安全命名空間。使用過濾器鏈映射的舊語法仍然受支持,但不贊成使用構造函數參數注入。
可以使用請求匹配器引用屬性來指定一個請求匹配器實例,以實現更強大的匹配,而不是路徑模式。
當瀏覽器不支持cookies,并且jsessionid參數被附加到分號后的URL時,您可能已經看到了這一點。然而,RFC允許在URL的任何路徑段中存在這些參數。
一旦請求離開FilterChainProxy,將返回原始值,因此應用程序仍然可以使用原始值。
因此,例如,原始請求路徑/secure;hack = 1/somefile . html;hack=2將作為/secure/somefile.html返回。
總結
以上是生活随笔為你收集整理的13. The Security Filter Chain(安全过滤链)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: wifi路由器重置路由器如何重设尼玛
- 下一篇: js代码执行过程