領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多Spring Security 6.4.1 是你處理身份驗證和授權的“一站式商店”,而這個版本簡直是重磅炸彈!發行說明充滿了可能性!
發行說明是騙人的!
我的意思是,它們並非全然是謊言。只是它們沒有很好地捕捉和傳達這個版本有多麼出色。這個版本使用者可見的新功能比以往許多版本都要多。這可能是我最喜歡的 Spring Security 版本,至少自從它開始擁有 Java 配置 DSL 以來是這樣!
看看那些釋出說明。看到了那些關於無密碼認證和一次性令牌登入的簡短章節了嗎?是的。那是謊言。這些東西應該有它們自己的篇章!我們會回過頭來談論它們。我保證。我們先快速看一下其他部分。太多的不同部分了。
@AuthorizeReturnObject功能正確配合,並且可以在@PreAuthorize和@PostAuthorize生命週期回撥中引用Bean。SecurityAnnotationScanners API提供了一種掃描安全註解的方式,可以將Spring Security的選擇和模板功能新增到自定義註解中。oauth2Login()方法現在接受OAurth2AuthorizationRequestResolver作為@Bean。ClientRegistrations現在支援外部獲取的配置。login page()logout+jwt型別的退出令牌OAuth2ClientHttpRequestInterceptor配置Spring RestClient來發出受保護的資源請求。在發出HTTP請求時,您可以讓它向下遊服務提供您的令牌。registrationId已簡化。application/samlmetadata+xml MIME型別。Remember Me cookieServerHttpSecurity現在將ServerWebExchangeFirewall物件作為Bean進行拾取。AclAuthorizationStrategyImpl支援RoleHierarchy型別,這也是一個相當新的型別!現在,讓我們回到關於無密碼認證和一次性令牌的討論。
讓我們來看一個簡單的應用程式。
我們將有一個需要鎖定的HTTP控制器
package com.example.bootiful_34.security;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.security.Principal;
import java.util.Map;
@Controller
@ResponseBody
class SecuredController {
@GetMapping("/admin")
Map<String, String> admin(Principal principal) {
return Map.of("admin", principal.getName());
}
@GetMapping("/")
Map<String, String> hello(Principal principal) {
return Map.of("user", principal.getName());
}
}
要鎖定它,我們需要定義一個SecurityFilterChain,其中包含一些常規項:HTTP表單登入、一些授權規則等。
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.authorizeHttpRequests(requests -> requests
.requestMatchers("/admin").hasRole("ADMIN")
.requestMatchers("/error").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
// ...
.build();
}
我們需要讓Spring Security瞭解我們系統中的使用者,所以讓我們提供一個UserDetailsService
package com.example.bootiful_34.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.http.MediaType;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@ImportRuntimeHints(UiResourcesRuntimeHintsRegistrar.class)
class SecurityConfiguration {
@Bean
UserDetailsService userDetailsService() {
var josh = User.withUsername("josh").password("pw").roles("USER").build();
var rob = User.withUsername("rob").password("pw").roles("USER", "ADMIN").build();
return new InMemoryUserDetailsManager(josh, rob);
}
// ...
}
這個應用程式有兩個使用者:josh和rob。josh只有一個角色USER,而rob同時擁有ADMIN和USER。
在非平凡的應用程式中,您應該使用一個指向身份提供者的替代`UserDetailsService`實現。或者,至少,一個不儲存純文字密碼的SQL資料庫。我在這裡註冊使用者和他們的密碼,但一個設計良好的系統將盡可能減少密碼的使用。您關於密碼的常識性智慧可能錯了。美國國家標準與技術研究所(美國商務部的一個組織)去年(2024年)釋出了其更新的密碼定義指南。
NIST特別出版物800-63B提供了關於建立、處理、續訂和儲存密碼(稱為“記憶秘密”)的具體指導,並概述了對一次性令牌和基於硬體的身份驗證器(例如,YubiKeys/WebAuthn)等替代方案的建議。讓我們來看看他們的一些建議。
如果您的系統需要密碼, there’s a lot to know. 幸運的是,Spring Security 可以為您完成以上大部分(甚至全部?)的指導。
使用者選擇的密碼必須至少八個字元長,由CSP(憑證服務提供商)隨機生成的密碼必須至少六個字元長。不鼓勵複雜性規則(例如,要求大小寫混合、數字和符號)。密碼不得被任意限制(例如,限制最大長度或排除某些字元)。密碼必須與常用、洩露或預期密碼的列表進行比對(例如,字典單詞、重複模式、服務特定術語)。如果密碼被標記為弱密碼,使用者必須選擇一個更健壯的替代方案。建議使用密碼強度計或反饋來幫助使用者建立健壯的密碼。該指南建議允許複製貼上功能,以鼓勵使用密碼管理器,並提供輸入的密碼的可選顯示,以最大程度地減少輸入錯誤。該文件建議將連續登入失敗次數限制在不超過100次,並實施驗證碼、增加延遲時間或其他自適應措施,以防止因濫用導致賬戶被鎖定。有趣的是,它建議重新驗證策略應根據保證級別而有所不同(例如,高保證級別需要每12小時或30分鐘無活動後重新驗證)。另一方面,密碼更改不應被任意或定期要求。只有在有證據表明存在洩露的情況下,才應強制更改。它建議使用單向金鑰派生函式(例如,PBKDF2、BCrypt或Argon2)對密碼進行雜湊和加鹽處理。Spring Security預設使用BCrypt。
NIST建議使用一次性令牌(OTP)等密碼替代方案。單因素OTP裝置生成基於時間或基於計數器的OTP。OTP必須具有密碼學安全性,並具有至少20位的熵。多因素OTP裝置在生成OTP之前需要第二個身份驗證因素(例如,PIN或生物特徵)。帶外身份驗證利用輔助通訊渠道(例如,移動裝置)進行OTP傳遞或確認,這需要安全的渠道並限制弱方法。還鼓勵使用基於硬體的身份驗證器(例如,YubiKeys、WebAuthn)。WebAuthn是FIDO聯盟的一部分,並被鼓勵作為一種健壯且抗網路釣魚的身份驗證方法。像YubiKeys這樣的硬體身份驗證器使用密碼學協議來確保安全。多因素密碼學裝置必須結合“你擁有的東西”(例如,YubiKey)與“你知道的東西”(例如,PIN)或“你是什麼”(例如,生物特徵)。金鑰應保留在防篡改硬體內,並且無法提取。
透過優先考慮這些方法,NIST強調了向多因素身份驗證(MFA)和密碼學解決方案過渡,作為比傳統密碼更安全的選擇。
因此,在Spring Security應用程式的上下文中,一次性令牌透過依賴於只有使用者自己才擁有的帶外因素來驗證使用者——也許是使用者接收簡訊的能力、訪問其電子郵件等。您可能以前在其他地方使用過此功能。您訪問一個網站,輸入您的使用者名稱,然後該網站會向您傳送一封包含您可以點選登入的連結的電子郵件。這些有時被稱為“魔法連結”。
Spring Security不提供與您喜歡的電子郵件提供商或訊息應用程式的整合。您可以使用Sendgrid、Twilio或數百萬個其他服務中的任何一個來實現。但Spring Security確實提供了建立和驗證連結的基礎架構。
這是我們在Spring Security配置中必須新增的一小段程式碼,以使其能夠列印
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
// ..
.oneTimeTokenLogin(configurer -> configurer.tokenGenerationSuccessHandler(
(request, response, oneTimeToken) -> {
var msg = "go to https://:8080/login/ott?token=" + oneTimeToken.getTokenValue();
System.out.println(msg);
response.setContentType(MediaType.TEXT_PLAIN_VALUE);
response.getWriter().print("you've got console mail!");
}))
// ..
.build();
}
看到了嗎?這只是一個單獨的lambda表示式,您可以在其中提供足夠的資訊來建立並向用戶傳送一個連結,一旦使用者點選該連結,就可以讓他們登入。簡單!在這個例子中,我只是透過點選控制檯中的連結來登入。同樣,您可能傳送電子郵件或其他更實際的方式。
這非常方便,並讓使用者不必擔心或——更糟糕的是——共享兩個密碼。希望他們已經鎖定了他們的電子郵件密碼!我寧願他們有一個不跨網站共享的良好密碼,而不是十幾個糟糕且共享的密碼。
另一種方法——另一層安全性——可能比文字連結更復雜,以阻止潛在的駭客接觸到。例如指紋、面部ID掃描或獨立的硬體加密狗。問題是:如何在需要的地方整合這些東西?為了讓它們正常工作,我們需要修改瀏覽器、伺服器端處理邏輯、作業系統等,以便它們都能說同一種標準協議。
您會很高興地知道,這幾乎是每個人都在做的事情。該協議名為WebAuthn,其背後的組織名為FIDO Alliance。FIDO Alliance得到了普遍支援!以下是其一些最傑出的成員。名單包括DELL、Apple、Google、Intuit、NTT DOCOMO、Microsoft、meta、LastPass、DashLane、Bank Of America、1Password、Intel、CISCO、CVS Health、American Express、VISA,以及無數其他公司。關鍵是,那些在乎金錢的人都在支援這種方法。瀏覽器也是如此!所有主流瀏覽器——Chrome、Safari、Edge、Firefox、iOS上的Safari、Android上的Chrome、iOS上的Chrome以及iOS上的Edge——都支援它。它無處不在!現在,多虧了Spring Security的這個版本,它也可以輕鬆地整合到您的應用程式中。
以下是我們Spring Security過濾器鏈示例中的相關配置
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
// ...
.webAuthn(c -> c
.rpId("localhost")
.rpName("bootiful passkeys")
.allowedOrigins("https://:8080")
)
// ...
.build();
}
重啟應用程式,然後登入到localhost:8080/webauthn/register。註冊您的無密碼認證。我在Apple生態系統中,所以它提示我在iPhone上進行FaceID,或者在我的macOS Apple Silicon筆記型電腦上使用TouchID。然後,瀏覽器將無密碼認證儲存在作業系統鑰匙串中。它現在已透過iCloud進行聯合。所以,我不僅有了一種有效的登入方式,而且它還與我的iCloud帳戶繫結,因此我可以在一臺裝置上使用Face ID,在另一臺裝置上使用Touch ID登入。無需額外工作!
要檢視效果,請登出:localhost:8080/logout。
安全性不僅非常出色,而且對使用者來說也更輕鬆!這不是很酷嗎?