Digest Authentication

本部分详细介绍了 Spring Security 如何提供 Digest AuthenticationDigestAuthenticationFilter 提供了 Digest Authentication

你不应在现代应用程序中使用摘要认证,因为它不被认为是安全的。最明显的问题是,你必须将密码存储为纯文本或加密或 MD5 格式。所有这些存储格式都被认为是不安全的。相反,你应使用单向自适应密码哈希(bCrypt、PBKDF2、SCrypt 等)来存储凭据,而摘要认证不支持此方式。

摘要身份验证尝试解决 Basic authentication 的许多弱点,具体而言,通过确保证书从不会以明文形式通过网络发送。许多 browsers support Digest Authentication

管理 HTTP 摘要身份验证的标准由 RFC 2617 定义,它更新 RFC 2069 规定的摘要身份验证标准的早期版本。大多数用户代理都实现 RFC 2617。Spring Security 的摘要身份验证支持与 RFC 2617 中规定的 “auth” 质量保护 (qop) 兼容,它还提供与 RFC 2069 的向后兼容性。如果您需要使用未加密的 HTTP(没有 TLS 或 HTTPS),并且希望最大程度地提高身份验证过程的安全性,摘要身份验证被视为更具吸引力的选择。但是,每个人都应该使用 HTTPS

摘要认证的核心是一个 “nonce”。这是服务器生成的一个值。Spring Security 的随机数遵循以下格式:

Digest Syntax
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 对不安全的纯文本 Password Storage 进行 configure。(请参阅 JavaDoc 中的 {security-api-url}org/springframework/security/crypto/password/NoOpPasswordEncoder.html[NoOpPasswordEncoder] 类。)以下提供使用 Java 配置配置摘要身份验证的示例:

Digest Authentication
  • Java

  • XML

@Autowired
UserDetailsService userDetailsService;

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

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

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	http
		// ...
		.exceptionHandling(e -> e.authenticationEntryPoint(authenticationEntryPoint()))
		.addFilterBefore(digestFilter());
	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>