我有一个受spring-security保护的带有spring-boot 2.0.1的Web应用程序。我将PersistentTokenRepository用于“记住我”,并将令牌存储在MySQL数据库中。

在服务器日志文件中,我看到很多使用CookieTheftException的堆栈跟踪。太多了,我很难相信真正的Cookies被盗了,但承担了某种错误的配置。通过添加一些分析代码,似乎只有移动浏览器受到影响。

Servlet.service() for servlet [dispatcherServlet] in context with path [/r] threw exception
  org.springframework.security.web.authentication.rememberme.CookieTheftException: Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
    at org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices.processAutoLoginCookie(PersistentTokenBasedRememberMeServices.java:119) ~[spring-security-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]


手动测试无法重现此错误。删除会话Cookie,但保留“记住我的Cookie”并向受限URL发出请求,将导致正常的身份验证会话。

这是我的安全配置的相关部分:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
    @Configuration
    public static class SecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Autowired
        private RememberMeServices rememberMeServices;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .rememberMe()
                    .key(rememberMeKey)
                    .rememberMeServices(rememberMeServices);
            ;
        }
    }

    /**
     * Key for RememberMeServices and RememberMeAuthenticationProvider.
     */
    private static final String rememberMeKey = "...";

    @Bean
    public RememberMeServices rememberMeServices(UserDetailsService userDetailsService, PersistentTokenRepository persistentTokenRepository) {
        PersistentTokenBasedRememberMeServices rememberMeServices = new AnalyzingPersistentTokenBasedRememberMeServices(
                rememberMeKey, userDetailsService, persistentTokenRepository);
        rememberMeServices.setTokenValiditySeconds((int) Duration.of(366L, ChronoUnit.DAYS).toSeconds());
        return rememberMeServices;
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository(JdbcTemplate jdbcTemplate) {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setJdbcTemplate(jdbcTemplate);
        return tokenRepository;
    }
}


AnalyzingPersistentTokenBasedRememberMeServicesPersistentTokenBasedRememberMeServices,并且在processAutoLoginCookie中有一些其他日志记录。

另一个特长是,我使用自定义的AuthenticationProvider,并且仅为RememberMe提供UserDetailsService。但是如上所述,手动测试就可以了。不过,用户报告他们注销得太频繁了(会话超时为24小时)。

有没有人遇到过这样的事情并且有解决方案?我会错过一些关键配置吗?

最佳答案

PersistentTokenBasedRememberMeServices不适合具有并发请求的应用程序,这些请求可能发送相同的令牌系列。

请参阅以下将近五年未解决的错误报告:

https://github.com/spring-projects/spring-security/issues/2648

https://github.com/spring-projects/spring-security/issues/3079

使用TokenBasedRememberMeServices没有这些问题。

09-16 05:35