摘要認證

本節詳細介紹 Spring Security 如何支援摘要認證 (Digest Authentication),這由 DigestAuthenticationFilter 提供。

在現代應用中不應使用摘要認證 (Digest Authentication),因為它不被認為是安全的。最明顯的問題是您必須以明文、加密或 MD5 格式儲存密碼。所有這些儲存格式都被認為是不安全的。相反,您應該使用單向自適應密碼雜湊(如 bCrypt、PBKDF2、SCrypt 等)來儲存憑據,而摘要認證不支援這些雜湊格式。

摘要認證試圖解決Basic 認證的許多弱點,特別是透過確保憑據永遠不會以明文形式在網路上傳輸。許多瀏覽器支援摘要認證

管理 HTTP 摘要認證的標準由RFC 2617定義,該標準更新了RFC 2069中規定的早期版本的摘要認證標準。大多數使用者代理都實現了 RFC 2617。Spring Security 的摘要認證支援相容 RFC 2617 規定的“auth”保護質量 (qop),同時也提供了與 RFC 2069 的向後相容性。如果您需要使用未加密的 HTTP(無 TLS 或 HTTPS)並希望最大化認證過程的安全性,摘要認證曾被視為一個更有吸引力的選項。然而,所有人都應該使用HTTPS

摘要認證的核心是一個“nonce”。這是伺服器生成的值。Spring Security 的 nonce 採用以下格式:

摘要語法
base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
expirationTime:   The date and time when the nonce expires, expressed in milliseconds
key:              A private key to prevent modification of the nonce token

您需要確保使用 NoOpPasswordEncoder 配置不安全的明文密碼儲存。 (參見 Javadoc 中的NoOpPasswordEncoder類。)以下是使用Java 配置摘要認證的示例:

摘要認證
  • Java

  • XML

@Autowired
UserDetailsService userDetailsService;

DigestAuthenticationEntryPoint authenticationEntryPoint() {
	DigestAuthenticationEntryPoint result = new DigestAuthenticationEntryPoint();
	result.setRealmName("My App Realm");
	result.setKey("3028472b-da34-4501-bfd8-a355c42bdf92");
	return result;
}

DigestAuthenticationFilter digestAuthenticationFilter() {
	DigestAuthenticationFilter result = new DigestAuthenticationFilter();
	result.setUserDetailsService(userDetailsService);
	result.setAuthenticationEntryPoint(authenticationEntryPoint());
	return result;
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	http
		// ...
		.exceptionHandling(e -> e.authenticationEntryPoint(authenticationEntryPoint()))
		.addFilter(digestAuthenticationFilter());
	return http.build();
}
<b:bean id="digestFilter"
        class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter"
    p:userDetailsService-ref="jdbcDaoImpl"
    p:authenticationEntryPoint-ref="digestEntryPoint"
/>

<b:bean id="digestEntryPoint"
        class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint"
    p:realmName="My App Realm"
	p:key="3028472b-da34-4501-bfd8-a355c42bdf92"
/>

<http>
	<!-- ... -->
	<custom-filter ref="userFilter" position="DIGEST_AUTH_FILTER"/>
</http>