摘要认证

本节详细介绍 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>