对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

以下步骤与有关身份验证执行方式的更改相关。Spring中文文档

在“记住我”中使用 SHA-256

该实现现在支持 Remember Me 令牌的 SHA-256,这是 Spring Security 6 中的默认设置。 默认情况下,此更改使实现更加安全,因为 MD5 已被证明是一种弱哈希算法,并且容易受到碰撞攻击和模块化差分攻击。TokenBasedRememberMeServicesSpring中文文档

新生成的令牌现在具有用于生成令牌的算法的信息,并且该信息用于匹配令牌。 如果算法名称不存在,则该属性用于检查令牌。 这允许从 MD5 平稳过渡到 SHA-256。matchingAlgorithmSpring中文文档

要选择加入新的 Spring Security 6 默认值来对令牌进行编码,同时仍然能够解码使用 MD5 编码的令牌,您可以将属性设置为 SHA-256,将属性设置为 MD5。 有关更多信息,请参阅参考文档API 文档encodingAlgorithmmatchingAlgorithmSpring中文文档

使用 Spring Security 6 默认值进行编码,使用 SHA-256 进行编码,使用 MD5 进行匹配
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http, RememberMeServices rememberMeServices) throws Exception {
        http
                // ...
                .rememberMe((remember) -> remember
                    .rememberMeServices(rememberMeServices)
                );
        return http.build();
    }

    @Bean
    RememberMeServices rememberMeServices(UserDetailsService userDetailsService) {
        RememberMeTokenAlgorithm encodingAlgorithm = RememberMeTokenAlgorithm.SHA256;
        TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices(myKey, userDetailsService, encodingAlgorithm);
        rememberMe.setMatchingAlgorithm(RememberMeTokenAlgorithm.MD5);
        return rememberMe;
    }

}
<http>
  <remember-me services-ref="rememberMeServices"/>
</http>

<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
    <property name="userDetailsService" ref="myUserDetailsService"/>
    <property name="key" value="springRocks"/>
    <property name="matchingAlgorithm" value="MD5"/>
    <property name="encodingAlgorithm" value="SHA256"/>
</bean>

在某个时候,您将希望完全迁移到 Spring Security 6 默认值。但是你怎么知道什么时候这样做是安全的呢? 假设你在 11 月 1 日使用 SHA-256 作为编码算法(如你在此处所做的那样)部署了应用程序,如果将属性的值设置为 N 天(默认值为 14),则可以在 11 月 1 日(在本例中为 11 月 15 日)之后迁移到 SHA-256 N 天。 届时,使用 MD5 生成的所有代币都将过期。tokenValiditySecondsSpring中文文档

使用 Spring Security 6 默认值 SHA-256 进行编码和匹配
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http, RememberMeServices rememberMeServices) throws Exception {
        http
                // ...
                .rememberMe((remember) -> remember
                    .rememberMeServices(rememberMeServices)
                );
        return http.build();
    }

    @Bean
    RememberMeServices rememberMeServices(UserDetailsService userDetailsService) {
        RememberMeTokenAlgorithm encodingAlgorithm = RememberMeTokenAlgorithm.SHA256;
        TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices(myKey, userDetailsService, encodingAlgorithm);
        rememberMe.setMatchingAlgorithm(RememberMeTokenAlgorithm.SHA256);
        return rememberMe;
    }

}
<http>
  <remember-me services-ref="rememberMeServices"/>
</http>

<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
    <property name="userDetailsService" ref="myUserDetailsService"/>
    <property name="key" value="springRocks"/>
    <property name="matchingAlgorithm" value="SHA256"/>
    <property name="encodingAlgorithm" value="SHA256"/>
</bean>

如果您对 Spring Security 6 默认值有疑问,您可以使用以下配置显式选择加入 5.8 默认值:Spring中文文档

将 MD5 用于编码和匹配算法
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http, RememberMeServices rememberMeServices) throws Exception {
        http
                // ...
                .rememberMe((remember) -> remember
                    .rememberMeServices(rememberMeServices)
                );
        return http.build();
    }

    @Bean
    RememberMeServices rememberMeServices(UserDetailsService userDetailsService) {
        RememberMeTokenAlgorithm encodingAlgorithm = RememberMeTokenAlgorithm.MD5;
        TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices(myKey, userDetailsService, encodingAlgorithm);
        rememberMe.setMatchingAlgorithm(RememberMeTokenAlgorithm.MD5);
        return rememberMe;
    }

}
<http>
  <remember-me services-ref="rememberMeServices"/>
</http>

<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
    <property name="userDetailsService" ref="myUserDetailsService"/>
    <property name="key" value="springRocks"/>
    <property name="matchingAlgorithm" value="MD5"/>
    <property name="encodingAlgorithm" value="MD5"/>
</bean>

传播 sAuthenticationServiceException

AuthenticationFilterAuthenticationServiceException传播到 AuthenticationEntryPoint。 由于 s 表示服务器端错误而不是客户端错误,因此在 6.0 中,此更改为将它们传播到容器。AuthenticationServiceExceptionSpring中文文档

配置为重新抛出AuthenticationFailureHandlerAuthenticationServiceException

要为 6.0 默认值做准备,请将实例与 a 重新抛出 s 连接,如下所示:AuthenticationFilterAuthenticationFailureHandlerAuthenticationServiceExceptionSpring中文文档

AuthenticationFilter authenticationFilter = new AuthenticationFilter(...);
AuthenticationEntryPointFailureHandler handler = new AuthenticationEntryPointFailureHandler(...);
handler.setRethrowAuthenticationServiceException(true);
authenticationFilter.setAuthenticationFailureHandler(handler);
val authenticationFilter: AuthenticationFilter = new AuthenticationFilter(...)
val handler: AuthenticationEntryPointFailureHandler = new AuthenticationEntryPointFailureHandler(...)
handler.setRethrowAuthenticationServiceException(true)
authenticationFilter.setAuthenticationFailureHandler(handler)
<bean id="authenticationFilter" class="org.springframework.security.web.authentication.AuthenticationFilter">
    <!-- ... -->
    <property ref="authenticationFailureHandler"/>
</bean>

<bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler">
    <property name="rethrowAuthenticationServiceException" value="true"/>
</bean>

选择退出步骤

如果重新抛出 s 会给您带来麻烦,您可以将值设置为 false,而不是采用 6.0 默认值,如下所示:AuthenticationServiceExceptionSpring中文文档

AuthenticationFilter authenticationFilter = new AuthenticationFilter(...);
AuthenticationEntryPointFailureHandler handler = new AuthenticationEntryPointFailureHandler(...);
handler.setRethrowAuthenticationServiceException(false);
authenticationFilter.setAuthenticationFailureHandler(handler);
val authenticationFilter: AuthenticationFilter = new AuthenticationFilter(...)
val handler: AuthenticationEntryPointFailureHandler = new AuthenticationEntryPointFailureHandler(...)
handler.setRethrowAuthenticationServiceException(false)
authenticationFilter.setAuthenticationFailureHandler(handler)
<bean id="authenticationFilter" class="org.springframework.security.web.authentication.AuthenticationFilter">
    <!-- ... -->
    <property ref="authenticationFailureHandler"/>
</bean>

<bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler">
    <property name="rethrowAuthenticationServiceException" value="false"/>
</bean>