Spring Security:用戶和Spring應用之間的安全屏障

摘要:Spring Security是一個安全框架,作為Spring家族的一員。

本文分享自華為雲社區《【雲駐共創】深入淺出Spring Security》,作者:香菜聊遊戲。

一、前言

1.歷史

Spring Security最早叫Acegi Security,這個名稱並不是說它和Spring就沒有關係,它依然是為Spring框架提供安全支持的。Acegi Security基於Spring,可以幫助我們為項目建立豐富的角色與權限管理系統。Acegi Security雖然好用,但是最為人詬病的則是它臃腫繁瑣的配置,這一問題最終也遺傳給了Spring Security。Acegi Security最終被併入Spring Security項目中,並於2008年4月發佈了改名後的第一個版本Spring Security 2.0.0。

2.對比

和Shiro相比,Spring Security重量級並且配置繁瑣。其實自從Spring Boot推出後,就徹底顛覆了傳統了JavaEE開發,自動化配置讓許多事情變得非常容易。在一個Spring Boot項目中,我們甚至只需要引入一個依賴,不需要任何額外配置,項目的所有接口就會被自動保護起來了。在Spring Cloud中很多涉及安全管理的問題,也是一個Spring Security依賴兩行配置就能搞定,在和Spring家族的產品一起使用時,Spring Security的優勢就非常明顯了。因此在微服務時代,我們不需要糾結要不要學習Spring Security,我們要考慮的是如何快速掌握Spring Security,並且能夠使用Spring Security實現我們微服務的安全管理。

3.為什麼選擇

不同於其他領域,在Java企業級開發中,安全管理方面的框架非常少,一般來說,主要有三種方案:

• Shiro

• Spring Security

• 開發者自己實現

Shiro本身是一個老牌的安全管理框架,有着眾多的優點,例如輕量、簡單、易於集成,可以在JavaSE環境中使用等。不過在微服務面前,它無法充分展示自己的優勢。也有開發者選擇自己實現安全管理,不過一個系統的安全,不僅僅是登錄和權限控制這麼簡單,我們還要考慮各種各樣可能存在的網絡攻擊以及防禦策略,從這個角度來說,只有大公司才有足夠的人力物力去支持這件事情。 Spring Security作為Spring家族的一員,在和Spring家族的其他成員進行整合時,具有其他框架無可比擬的優勢,同時對OAuth2有着良好的支持,再加上Spring Cloud對Spring Security的不斷加持,讓Spring Security成為微服務項目的首選安全管理方案。

二、Spring Security簡介

Spring Security的核心功能

對於一個安全管理框架而言,無論是Shiro還是Spring Security,最核心的功能,無非就是如下兩方面認證和授權。

1.認證

認證就是身份驗證(你是誰?),作為一個開放的平台,我們還可以通過引入第三方依賴來支持更多的認證方式,同時,如果這些認證方式無法滿足我們的需求,我們也可以自定義認證邏輯,特別是當我們和一些「老破舊」的系統進行集成時,自定義 認證邏輯就顯得非常重要了。

2.授權

授權就是訪問控制(你可以做什麼?),無論採用了哪種認證方式,都不影響在Spring Security中使用授權功能。Spring Security支持基於URL的請求授權、支持方法訪問授權、支持SpEL訪問控制、支持域對象安全(ACL),同時也支持動態權限配置、支持RBAC權限模型等,總之我們常見的權限管理需求,Spring Security基本上都是支持的。

3.其他

在認證和授權這兩個核心功能之外,Spring Security還提供了很多安全管理的「周邊功能」,這也是一個非常重要的特色,例如:

• 密碼加密

• RememberMe

• 會話固定攻擊防禦

• CSRF防禦

• Http防火牆

Spring Security 的整體架構

1.認證和授權

在Spring Security的架構設計中,認證(Authentication)和授權(Authorization)是分開的,無論使用什麼樣的認證方式,都不會影響授權,這是兩個獨立的存在,這種獨立帶來的好處之一,就是Spring Security可以非常方便地整合一些外部的認證方案。在Spring Security中,用戶的認證信息主要由Authentication的實現類來保存,當用戶使用用戶名/密碼登錄或使用Remember-me登錄時,都會對應一個不同的Authentication實例。Spring Security中的認證工作主要是由AuthenticationManager接口來負責,在該接口中通過authenticate方法來做認證。AuthenticationManager最主要的實現類是ProviderManager,ProviderManager管理了眾多的 AuthenticationProvider實例。在一次完整的認證流程中,可能會同時存在多個AuthenticationProvider,多個AuthenticationProvider統一由ProviderManager來管理。同時,ProviderManager具有一個可選的parent,如果所有的AuthenticationProvider都認證失敗,那麼就會調用parent進行認證。

2.關鍵接口

在Spring Security的授權體系中,有兩個關鍵接口: AccessDecisionManager 和AccessDecisionVoter。

AccessDecisionVoter是一個投票器,投票器會檢查用戶是否具備應有的角色,進而投出贊成、反對或者棄權票。

AccessDecisionManager則是一個決策器,來決定此次訪問是否被允許。

3.Web安全

在Spring Security中,認證、授權等功能都是基於過濾器來完成的。開發者所見到的Spring Security提供的功能,都是通過這些過濾器來實現的,這些過濾器按照既定的優先級排列,最終形成一個過濾器鏈。開發者也可以自定義過濾器,並通過@Order註解去調整自定義過濾器在過濾器鏈中的位置。需要注意的是,默認過濾器並不是直接放在Web項目的原生過濾器鏈中,而是通過一個FilterChainProxy來統一管理。Spring Security中的過濾器鏈通過FilterChainProxy嵌入到Web項目的原生過濾器鏈中。在Spring Security中,這樣的過濾器鏈不僅僅只有一個可能會有多個。當存在多個過濾器鏈時,多個過濾器鏈之間要指定優先級,當請求到達後,會從FilterChainProxy進行分發,先和哪個過濾器鏈匹配上,就用哪個過濾器鏈進行處理。

三、Spring Security認證流程分析

1.基本認證

在Spring Boot項目中使用Spring Security非常方便,創建一個新的SpringBoot項目,我們只需要引入web和Spring Security依賴即可。

Maven 項目加入下面的依賴

引入依賴後,項目中的所有接口就都被保護起來了,此時訪問接口就可以看到登錄頁面了。

2.Spring Security認證流程分析

AuthenticationManafer是一個認證管理器。它定義了Spring Security過濾器要如何執行認證操作,在認證成功後,會返回一個Authentication對象,這個對象會被設置到SecurityContextHodler中。AuthenticationManafer是一個接口,它有着諸多的實現類,開發者可以自定義AuthenticationManafer的實現類,不過在實際應用中,我們使用最多的是ProviderManager,在Spring Security框架中,默認也是使用ProviderManager。

1)AuthentucationProvider

Spring Security支持多種不同的認證方式,不同的認證方式對應不同的身份類型,AuthentucationProvider就是針對不同的身份類型執行具體的身份認證。例如,常見的DaoAuthenticationProvider用來支持用戶名密碼登錄認證, RememberMeAuthenticationProvider用來支持記住我的認證。

2)ProviderManager

在Spring Security中,由於系統可能同時支持多種不同的認證方式,例如同時支持用戶名/密碼認證、RememberMe認證、手機號碼動態認證等,而不同的認證方式對應了不同的AuthenticationProvider,所以一個完整的認證流程可能由多個AuthenticationProvider來提供。多個AuthenticationProvider將組成一個列表這個列表將由ProviderManagerf代理。換句話說,在ProviderManager中存在一個AuthenticationProvider表在ProviderManager中遍歷列表中的每一個AuthenticationProvider去執行身份認證,最終得到認證結果。ProviderManager本身也可以再配置一個AuthenticationManager作為parent,這樣當ProviderManager認證失敗之後,就可以進入到parent中再次進行認證。理論上來說,ProviderManager的parent可以是任意類型的AuthenticationManager,但是通常都是由ProviderManager來扮演parent的角色,也就是ProviderManager是ProviderManager的parent。

3)AbstractAuthenticationProcessingFilter

AbstractAuthenticationProcessingFilter用來處理任何提交給它的身份認證。

四、Spring Security密碼加密

1.常見實現類

BcryptPasswordEncoder

Argon2PasswordEncoder

Pbkdf2PasswordEncoder

ScryptPasswordEncoder

2.DelegatingPasswordEncoder

DelegatingPasswordEncoder是一個代理類,而並非一種全新的密碼加密方案。主要用來代理不同的密碼加密方案。為什麼採用而不是某一個具體加密方式作為默認的密碼加密方案呢?主要考慮了如下三方面的因素:

(1)兼容性:使用DelegatingPasswordEncoder可以幫助許多使用舊密碼加密方式的系統順利遷移到中,它允許在同一個系統中同時存在多種不同的密碼加密方案。

(2)便捷性:密碼存儲的最佳方案不可能一直不變,如果使用DelegatingPasswordEncoder作為默認的密碼加密方案,當需要修改加密方案時,只需要修改很小一部分代碼就可以實現。

(3)穩定性:作為一個框架,不能經常進行重大更改,而使用DelegatingPasswordEncoder可以方便地對密碼進行升級(自動從一個加密方案升級到另外一個加密方案)。

五、Spring Security會話管理

1.什麼是會話

當瀏覽器調用登錄接口登錄成功後,服務端會和瀏覽器之間建立一個會話(Session),瀏覽器在每次發送請求時都會攜帶一個SessionId,服務端則根據這個SessionId來判斷用戶身份。當瀏覽器關閉後,服務端的Session並不會自動銷毀,需要開發者手動在服務端調用Session銷毀方法,或者等Session過期時間到了自動銷毀。在Spring Security中,與HttpSession相關的功能由 SessionManagementFilter和SessionAuthenticationStrategy接口來處理, 過濾器將Session相關操作委託給SessionAuthenticationStrategy接口去完成。

2.什麼是會話並發管理?

會話並發管理就是指在當前系統中,同一個用戶可以同時創建多少個會話,如果一台設備對應一個會話,那麼也可以簡單理解為同一個用戶可以同時在多少台設備上進行登錄。默認情況下,同一用戶在多少台設備上登錄並沒有限制,不過開發者可以在Spring Security中對此進行配置。

3.擠下線

當會話並發數達到限制時,新的會話將之前舊的會話擠下線,舊的登錄會話失效。配置如下

4.限制登錄

當會話並發數達到限制時,新的會話將被限制創建,除非舊的會話主動退出登錄。

5.什麼是會話固定攻擊

會話固定攻擊(Session fixation attacks)是一種潛在的風險,惡意攻擊者有可能通過訪問當前應用程序來創建會話,然後誘導用戶以相同的會話登錄(通常是將會話作為參數放在請求鏈接中,然後誘導用戶去單擊),進而獲取用戶的登錄身份。

1.會話固定攻擊步驟

(1)攻擊者自己可以正常訪問javaboy網站,在訪問的過程中,網站給攻擊者分配了一個。

(2)攻擊者利用自己拿到的sessionId構造一個javaboy網站的鏈接,並把該鏈接發送給受害者。

(3)受害者使用該鏈接登錄javaboy網站(該鏈接中含有sessionId),登錄成功後,一個合法的會話就成功建立了。

(4)攻擊者利用手裡的冒充受害者。

2.會話固定攻擊防禦策略

Spring Security中從三方面入手防範會話固定攻擊:

(1)Spring Security中默認自帶了Http防火牆,如果sessionId放在地址欄中,這個請求就會直接被攔截下來。

(2)在http響應的Set-Cookie字段中有HttpOnly屬性,這樣避免了通過XSS攻擊來獲取Cookie中的會話信息, 進而達成會話固定攻擊。

(3)在用戶登錄成功後,改變SessionId, Spring Security中默認實現了該種方案。

六、Spring Security防火牆

1.什麼是HttpFireWall

HttpFirewall是Spring Security提供的Http防火牆,它可以用於拒絕潛在的危險請求或者包裝這些請求進而控制其行為。通過可以對各種非法請求提前進行攔截並處理,降低損失。

2.Spring Security 中的HttpFirewall兩個實現類

• DefaultHttpFirewall雖然名字中包含Default,但這並不是框架默認使用的Http防火牆,它只是一個檢查相對寬鬆的防火牆。

HttpFirewall普通模式就是使用DefaultHttpFirewall,該類的校驗規則就要簡單很多。一般來說,並不建議開發者在項目中使用DefaultHttpFirewall,因為相比於StrictHttp Firewal,DefaultHttpFirewall的安全性要差很多。

• StricHttpFirewall 這是一個檢查嚴格的Http防火牆,也是框架默認使用的 Http防火牆

嚴格模式下對請求做出了諸多限制:

1) rejectForbiddenHttpMethod:校驗請求方法是否合法。

2)rejectedBlacklistedUrls:校驗請求中的非法字符。

3) rejectedUntrustedHosts:檢驗主機信息。

4)isNormalized:判斷參數格式是否合法。

5)containsOnlyPrintableAsciCharacters: 判斷請求字符是否合法。

總結

Spring Security是一個安全框架,作為Spring家族的一員,可以簡單地認為 Spring Security是放在用戶和Spring應用之間的一個安全屏障,每一個web請求都先要經過Spring Security 進行Authenticate和 Authoration驗證,其核心就是一組過濾器鏈。

 

點擊關注,第一時間了解華為雲新鮮技術~