spring security源码分析之web包分析
Spring 是一個非常流行和成功的 Java 應(yīng)用開發(fā)框架。Spring Security 基于 Spring 框架,提供了一套 Web 應(yīng)用安全性的完整解決方案。一般來說,Web 應(yīng)用的安全性包括用戶認(rèn)證(Authentication)和用戶授權(quán)(Authorization)兩個部分。用戶認(rèn)證指的是驗證某個用戶是否為系統(tǒng)中的合法主體,也就是說用戶能否訪問該系統(tǒng)。用戶認(rèn)證一般要求用戶提供用戶名和密碼。系統(tǒng)通過校驗用戶名和密碼來完成認(rèn)證過程。用戶授權(quán)指的是驗證某個用戶是否有權(quán)限執(zhí)行某個操作。在一個系統(tǒng)中,不同用戶所具有的權(quán)限是不同的。比如對一個文件來說,有的用戶只能進(jìn)行讀取,而有的用戶可以進(jìn)行修改。一般來說,系統(tǒng)會為不同的用戶分配不同的角色,而每個角色則對應(yīng)一系列的權(quán)限。
對于上面提到的兩種應(yīng)用情景,Spring Security 框架都有很好的支持。在用戶認(rèn)證方面,Spring Security 框架支持主流的認(rèn)證方式,包括 HTTP 基本認(rèn)證、HTTP 表單驗證、HTTP 摘要認(rèn)證、OpenID 和 LDAP 等。在用戶授權(quán)方面,Spring Security 提供了基于角色的訪問控制和訪問控制列表(Access Control List,ACL),可以對應(yīng)用中的領(lǐng)域?qū)ο筮M(jìn)行細(xì)粒度的控制。
本文先從web包來分析spring-security提供的安全保護(hù)。
1. access模塊:
其中,ExceptionTranslationFilter:處理過濾器鏈拋出的所有AccessDeniedException和AuthenticationException異常.
WebInvocationPrivilegeEvaluator:允許用戶來決定他們是否有訪問特定web url的權(quán)限。
? ?1.1 channel包:確保從指定傳輸通道接收web請求。
其中,
ChannelProcessingFilter: 確保一個web請求通過要求的channel。在內(nèi)部使用FilterInvocation來表示request請求,允許使用FilterInvoctionSecurityMetaDataSource來查詢應(yīng)用之上的屬性。代理ChannelDecisionManager來處理真實的通道安全Decision和必須的action。若響應(yīng)由ChannelDecisionManager來提交,ChannelProcessingFilter將不會處理。
下面的示例強(qiáng)制將登陸表單和對/secure路徑下的訪問都通過https來訪問。
<bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter"><property name="channelDecisionManager" ref="channelDecisionManager"/><property name="securityMetadataSource"><security:filter-security-metadata-source path-type="regex"><security:intercept-url pattern="\A/secure/.*\Z" access="REQUIRES_SECURE_CHANNEL"/><security:intercept-url pattern="\A/login.jsp.*\Z" access="REQUIRES_SECURE_CHANNEL"/><security:intercept-url pattern="\A/.*\Z" access="ANY_CHANNEL"/></security:filter-security-metadata-source></property> </bean><bean id="channelDecisionManager" class="org.springframework.security.web.access.channel.ChannelDecisionManagerImpl"><property name="channelProcessors"><list><ref bean="secureChannelProcessor"/><ref bean="insecureChannelProcessor"/></list></property> </bean><bean id="secureChannelProcessor" class="org.springframework.security.web.access.channel.SecureChannelProcessor"/> <bean id="insecureChannelProcessor" class="org.springframework.security.web.access.channel.InsecureChannelProcessor"/> channelDecisionManager:確定一個web channel是否提供了足夠的安全性。ChannelProcessor:確定一個web channel是否滿足特定安全條件。
ChannelEntryPoint:由ChannelProcessor使用來啟動一個web channel。
?1.2 expression包:
?
SecurityExpressionHandler 是一個門面,它將內(nèi)在的表達(dá)式對象實現(xiàn)和spring security對安全表達(dá)式的需求分離開來。
DefaultWebSecurityExpressionHandler是SecurityExpressionHandler的默認(rèn)實現(xiàn)。
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi);root.setPermissionEvaluator(getPermissionEvaluator());root.setTrustResolver(trustResolver);root.setRoleHierarchy(getRoleHierarchy());return root;}?1.3 intercept包:增強(qiáng)http請求的安全性,特別是url請求。
?
?
其中,FilterSecurityInterceptor 通過實現(xiàn)了filter來增加http資源的安全性。這個安全攔截器需要FilterInvocationSecurityMedataSource。
?
2. authentication模塊
認(rèn)證處理機(jī)制,支持多種協(xié)議如BASIC,CAS,form login等提交認(rèn)證信息。
? ? 2.1 logout和rememberme 包
?其中
LogoutFilter記錄用戶的退出,它包含了一組Logouthandler。這些hangler應(yīng)用按照順序排序,順序是你想調(diào)用TockenBasedRememberMeServices和securityContxtLogoutHander的順序。退出后,將由LogoutSucessHandler或者LogoutSuccesUrl來決定跳轉(zhuǎn)到哪里。到底由誰確定依賴于創(chuàng)建LogoutFilter使用的構(gòu)造方法。
RememberMeAuthenticationFilter檢查SecurityContext中是否有Authentication對象,并且當(dāng)有RememberMeServices實現(xiàn)了該請求時將一個remember-me authentication token設(shè)置到SecurityContext中。這個過濾器會調(diào)用RememberMeServices實現(xiàn)的autoLogin方法,如果上述方法返回一個非空的Authentication對象,會被傳遞到AuthenticationManager,這樣任何特定authentication將可以完成。若Authentication結(jié)果返回成功,它將會被設(shè)置到SecurityContext中。
? 如果認(rèn)證成功,一個InteractiveAuthenticationSuccessEvent時間將會發(fā)布到application context中,若認(rèn)證不成功,則不會有事件發(fā)布,因為不成功的話會記錄成特定AuthenticationManager的應(yīng)用事件。 正常情況下,不管Authentication是成功還是失敗,都會允許處理請求request。如果需要控制特定認(rèn)證用戶的訪問目的,可以將AuthenticationSuccessHandler注入其中。
2.2 peauth包
支持已認(rèn)證的場景--spring 假定請求request已經(jīng)被外部配置系統(tǒng)認(rèn)證通過的場景。
AuthenticationDetailsSource:給特定的web請求request提供一個Authentication接口提供一個getDetails()方法
J2eePreAuthenticatedProcessingFilter:基于j2ee容器認(rèn)證機(jī)制的過濾器,它將使用j2ee 用戶principal名稱作為預(yù)先完成認(rèn)證的principal。
WebSpherePreAuthenticatedProcessingFilter:基于Websphere認(rèn)證的過濾器,它將使用Websphere RunAs 用戶principal名稱作為先完成認(rèn)證的principal。
X509AuthenticationFilter:負(fù)責(zé)處理要求未認(rèn)證用戶提供客戶端證書的請求。如果這個請求包含了合法的證書,它將會使SubjectDnX509PrincipalExtractor抽取出安全實體.
RequestHeaderAuthenticationFilter:一個簡單的預(yù)先認(rèn)證完成過濾器,它從用戶的請求頭獲取用戶名,使用在諸如CA siteminder系統(tǒng)等。
2.3 session和switchuser
session包:提供一個新認(rèn)證用戶處理session相關(guān)行為的策略接口和實現(xiàn)類
switchuser包:提供一個基于http的具有切換用戶能力的包。類似于linux中的su命令。
?SessionAuthenticationStrategy:在一次認(rèn)證過程中對httpSession相關(guān)的行為允許可插拔支持。典型應(yīng)用場景是確認(rèn)session是否存在或者改變session id來保證基于session攻擊的安全。
SwitchUserFilter:高權(quán)限用戶向低權(quán)限用戶切換 。
2. 4 ui包
DefaultLoginPageGeneratingFilter:當(dāng)一個用戶沒有配置login頁面時使用。僅當(dāng)跳轉(zhuǎn)到login頁面時用到。
2.5 www包
BasicAuthenticationFilter:處理一個http請求的basic認(rèn)證頭,將結(jié)果放入SecurityContextHolder。
總之,該過濾器負(fù)責(zé)處理具有basic認(rèn)證scheme和base64編碼的username:password token的http請求頭消息.例如,認(rèn)證一個名為"Aladdin"的用戶,其密碼為“open sesame” ,其頭部如下:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
該過濾器不但可以用來為遠(yuǎn)程協(xié)議客戶端(如hessian和soap)提供basic認(rèn)證服務(wù),還可以為標(biāo)準(zhǔn)的用戶代理(如ie和netscape)提供basic認(rèn)證服務(wù)。如果認(rèn)證成功,認(rèn)證結(jié)果Authentication對象將會放入SecurityContextHolder之中。如果認(rèn)證失敗并且<ignoreFailure>設(shè)置為false(默認(rèn)),將會調(diào)用AuthenticationEntryPoint實現(xiàn)類(除非<ignoreFailure>屬性被設(shè)置為true)。通常情況下是BasicAuthenticationEntryPoint,它提醒用戶通過Basic認(rèn)證方式重新認(rèn)證。因basic認(rèn)證協(xié)議的簡單和廣泛部署,它是一個非常有吸引力的協(xié)議。然而,由于該協(xié)議通過明確的text傳遞密碼,因此它不適用于很多應(yīng)用場景。spring security提供的Digest認(rèn)證可以在這些場景中替換Basic認(rèn)證。
注意:若設(shè)置了RememberMeService,該filter將自動給用戶返回remember-me細(xì)節(jié)。
DigestAuthenticationFilter:參照BasicAuthenticationFilter,注意:digest認(rèn)證的缺點,盡管digest認(rèn)證方式比basic認(rèn)證方式更全面、更安全,但Rfc2617第四部分詳細(xì)討論了digest認(rèn)證方式比basic認(rèn)證方式的好處,也論述了digest的缺陷。
3.bind模塊
??AuthenticationPrincipal注解:綁定一個方法的參數(shù)或者方法到Authentication的getPrincipal()方法。必須指明,參數(shù)應(yīng)該解析到當(dāng)前用戶而不是可以在表單編輯的用戶。示例如下:
@Controller public class MyController {@RequestMapping("/user/current/show")public String show(@AuthenticationPrincipal CustomUser customUser) {// do something with CustomUserreturn "view";}AuthenticationPrincipalArgumentResolver:解析AuthenticationPrincipal注解。上述例子也可以這樣做:
@Target({ ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @AuthenticationPrincipal public @interface CurrentUser {}@Controllerpublic class MyController {@RequestMapping("/user/current/show")public String show(@CurrentUser CustomUser customUser) {// do something with CustomUserreturn "view";}4.上下文context模塊
同步SecurityContextPersistenceFilter:從配置的SecurityContextRepository而不是request中獲取信息存到SecurityContextHolder,并且當(dāng)請求結(jié)束清理contextHolder時將值存回repository中(默認(rèn)使用HttpSessionSecurityContextRepository).在該過濾器中每一個請求僅執(zhí)行一次,該filter需在任何認(rèn)證處理機(jī)制其作用之前執(zhí)行。認(rèn)證處理機(jī)制如basic,cas等期望在執(zhí)行時從SecurityContextHolder中獲取SecurityContext。
異步WebAsyncManagerIntegrationFilter:提供了對securityContext和WebAsyncManager的集成。方式是通過SecurityContextCallableProcessingInterceptor的beforeConcurrentHandling(NativeWebRequest, Callable)方法來講SecurityContext設(shè)置到Callable上。
SecurityContextCallableProcessingInterceptor:支持spring mvc Callable集成。當(dāng)SecurityContextCallableProcessingInterceptor執(zhí)行preProcess(NativeWebRequest, Callable)方法時將注入的SecurityContext傳遞給SecurityContextHolder。
@Overridepublic <T> void preProcess(NativeWebRequest request, Callable<T> task) throws Exception {SecurityContextHolder.setContext(securityContext);}同樣清楚的是,SecurityContextCallableProcessingInterceptor在執(zhí)行postProcess(NativeWebRequest, Callable, Object)方法時調(diào)用SecurityContextHolder的clearContext()。
@Overridepublic <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) throws Exception {SecurityContextHolder.clearContext();}5 csrf模塊
Cross-site request forgery跨站請求偽造,也被稱為“one click attack”或者session riding,通常縮寫為CSRF或者XSRF,是一種對網(wǎng)站的惡意利用。
CsrfException:當(dāng)一個HttpServletRequest沒有有效的CsrfToken或者沒有CsrfToken時拋出的異常,有兩個子類:InvalidCsrfTokenException和MissingCsrfTokenException。
CsrfToken提供了一個期望的csrf token信息。默認(rèn)實現(xiàn)為DefaultCsrfToken,還有一個內(nèi)部實現(xiàn)類SaveOnAccessCsrfToken。
CsrfTokenRepository:將crsfToken與HttpServletRequest關(guān)聯(lián)起來,使之能關(guān)聯(lián)CsrfToken的api。例如,可以存儲到HttpSesssion中。默認(rèn)實現(xiàn)為HttpSessionCsrfTokenRepository。
?CsrfFilter:通過使用同步token模式來進(jìn)行csrf防護(hù)。
CsrfLogoutHandler 負(fù)責(zé)在退出時移除csrfToken。調(diào)用時在LogoutFilter中的logout方法中:
for (LogoutHandler handler : handlers) {handler.logout(request, response, auth);}6. Debug模塊
??DebugFilter:spring security的調(diào)試過濾器。為幫助用戶理解請求request是如何被spring security處理的,使用日志記錄諸如session創(chuàng)建等消息。同時也會記錄一些別的相關(guān)消息。
? Logger封裝了apache commons-logging。
7.firewall模塊
??HttpFirewall接口時為了阻止?jié)撛谕{的請求而將請求進(jìn)行封裝來控制這些請求的行為的接口。
?DefaultHttpFirewall是默認(rèn)實現(xiàn)。主要是檢查一個路徑是否合法:
/*** Checks whether a path is normalized (doesn't contain path traversal sequences like "./", "/../" or "/.")** @param path the path to test* @return true if the path doesn't contain any path-traversal character sequences.*/private boolean isNormalized(String path) {if (path == null) {return true;}for (int j = path.length(); j > 0;) {int i = path.lastIndexOf('/', j - 1);int gap = j - i;if (gap == 2 && path.charAt(i+1) == '.') {// ".", "/./" or "/."return false;} else if (gap == 3 && path.charAt(i+1) == '.'&& path.charAt(i+2) == '.') {return false;}j = i;}return true;}FirewalledRequest是個抽象類,是請求request的封裝,返回一個HttpFirewall接口。不同之處在于reset方法,該方法允許當(dāng)請求離開security filter chain時重置部分或者全部狀態(tài)。默認(rèn)實現(xiàn)為RequestWrapper。
8. header模塊
HeaderWriter是一個向HttpServletResponse寫入http請求頭的約定。
HeaderWriterFilter向當(dāng)前請求中增加http請求頭的過濾器,為瀏覽器保護(hù)增加特定的http請求頭。如X-FRAME-options(X-Frame-Options response header 可用于指示是否應(yīng)該允許瀏覽器呈現(xiàn)在一個頁面<FRAME> 或 <IFRAME>中. 以確保網(wǎng)站內(nèi)容是不是嵌入到其它網(wǎng)站.?)、x-xss-protection(在正常情況下,通過下面的HTTP header,就可以完美的關(guān)閉發(fā)送這個header的頁面XSS保護(hù)特性了。X-XSS-Protection: 0)和x-content-type-options(這個header主要用來防止在IE9、chrome和safari中的MIME類型混淆攻擊。firefox目前對此還存在爭議。通常瀏覽器可以通過嗅探內(nèi)容本身的方法來決定它是什么類型,而不是看響應(yīng)中的content-type值。通過設(shè)置 X-Content-Type-Options:如果content-type和期望的類型匹配,則不需要嗅探,只能從外部加載確定類型的資源。)。
9.session模塊
ConcurrentSessionFilter:這個filter有兩個功能。第一:它調(diào)用SessionRegistry的refreshLastRequest(String)方法來保證注冊的session通常擁有正確的最后一次更新時間。
第二:它從每個請求的SessionRegistry中檢索SessionInformation,并檢查session是否已經(jīng)標(biāo)示為過期。若標(biāo)示為過期,則調(diào)用配置的所有l(wèi)ogout handler(在LogoutFilter中調(diào)用),通常的場景是使session過期。此時會跳轉(zhuǎn)到指定的expiredURL,session過期會通過注冊在<web.xml>的HttpSessionEventPublisher產(chǎn)生一個HttpSessionDestroyedEvent事件。
10 小結(jié)
? ?Spring Security對Web安全性的支持大量地依賴于Servlet過濾器。這些過濾器攔截進(jìn)入請求,并且在應(yīng)用程序處理該請求之前進(jìn)行某些安全處理。 Spring Security提供有若干個過濾器,它們能夠攔截Servlet請求,并將這些請求轉(zhuǎn)給認(rèn)證和訪問決策管理器處理,從而增強(qiáng)安全性。
參考文獻(xiàn):
1.?http://www.ibm.com/developerworks/cn/java/j-lo-springsecurity/
2.?http://baike.baidu.com/link?url=mk6ZedYayBqvXehW094XdImcU9g2SGLgt-gmdKYAF17db97_mEloPPm3K-1eqqEymefNNO30b2CTGw2Ryf6amq
?
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/4522408.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的spring security源码分析之web包分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Spring源码解析之:Spring S
- 下一篇: Spring SqlRowSet exa
