인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

윤지상님의 프로필 이미지
윤지상

작성한 질문수

스프링 시큐리티

7) Remember Me 인증 필터 : RememberMeAuthenticationFilter

Remember-me .CookieTheftException Exception 문의

작성

·

499

0

안녕하세요 ^^. 

강의 잘듣고 있습니다. 

리멤버미 토큰 관련해서 질문이 있습니다. 

스프링 시큐리티 리멤버미 기능을 이용하고 있는데요, 토큰 저장소는 DB 에 저장을 해놓고요. 

하지만 스프링 application 을 restart 하게 되면 .CookieTheftException Exception 이 터집니다. 디버깅해보니, 이전에 저장되어 있던 Token value 와 새로 인입된 Token Value 가 일치하지 않더라고요.. 

테스트 순서는 아래와 같습니다.

1. 리멤버미를 이용한 로그인 후 로그인 성공

2. DB 및 쿠키 remember-me 확인 완료

3. Springboot app 재시작 

4. front 페이지 새로고침 

5. RememberMeTokenRepository  -> updateToken 메소드 호출 되면서 token value DB update

( 이때 페이지 새로고침했다고 토큰이 새로 발행되는게 맞나요? 토큰 expire 시간이 지나지도 않았는데)

6. 기존 token value 와 신규 token value 불일치로 인한 RememberMeTokenRepository -> removeUserTokens 메소드 호출되면서 token 삭제 

7. .CookieTheftException 예외 터짐 

일단 어플리케이션 재기동 이후 페이지 새로고침을 하는 순간 기존에 토큰 값이 아닌 새로운 값이 업데이트 되는데, 업데이트된 토큰 값 과 기존의 토큰 값이 불일치 하니 당연히 에러가 터지겠죠.. 

근데 왜 업데이트가 되는지 이해가 잘 안되네요.. 

혹시 어플리케이션 재기동하게되면 리멤버미 기능을 이용해서 이미 로그인되어 있는 유저들은 어떻게 처리해야 좋을까요?

혹시 몰라 아래 로그 달아드릴게요.. 

강의 너무 감사합니다. 

2021-07-16 16:10:09.061  INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository        : remember-me token 획득
Hibernate: 
    select
        rememberme0_.series as series1_1_,
        rememberme0_.last_used as last_use2_1_,
        rememberme0_.token as token3_1_,
        rememberme0_.username as username4_1_ 
    from
        persistent_logins rememberme0_ 
    where
        rememberme0_.series=?
2021-07-16 16:10:09.262  INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository        : remember-me token 획득 tokne oulEuy+jZS+XqpkJfzYwBw==
2021-07-16 16:10:09.297  INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository        : remember-me token 업데이트 [ddCMgrk5Gm0hEqiH4LuvaQ==] [55vHBaBrKjGiA039ZzOH4w==]
Hibernate: 
    select
        rememberme0_.series as series1_1_,
        rememberme0_.last_used as last_use2_1_,
        rememberme0_.token as token3_1_,
        rememberme0_.username as username4_1_ 
    from
        persistent_logins rememberme0_ 
    where
        rememberme0_.series=?
Hibernate: 
    update
        persistent_logins 
    set
        last_used=?,
        token=?,
        username=? 
    where
        series=?
Hibernate: 
    select
        member0_.id as id1_18_,
        member0_.created_at as created_2_18_,
        member0_.updated_at as updated_3_18_,
        member0_.access_token as access_t4_18_,
        member0_.access_yn as access_y5_18_,
        member0_.account_type as account_6_18_,
        member0_.activated as activate7_18_,
        member0_.birth_date as birth_da8_18_,
        member0_.branch as branch9_18_,
        member0_.comment as comment10_18_,
        member0_.email_address as email_a11_18_,
        member0_.gender as gender12_18_,
        member0_.group_name as group_n13_18_,
        member0_.guide_count as guide_c14_18_,
        member0_.last_accessed_at as last_ac15_18_,
        member0_.name as name16_18_,
        member0_.password as passwor17_18_,
        member0_.phone as phone18_18_,
        member0_.point as point19_18_,
        member0_.position as positio20_18_,
        member0_.refresh_token as refresh21_18_ 
    from
        tb_member member0_ 
    where
        member0_.email_address=?
2021-07-16 16:10:09.403 ERROR 18296 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

java.lang.NullPointerException: null
	at org.springframework.security.authentication.AccountStatusUserDetailsChecker.check(AccountStatusUserDetailsChecker.java:41)
	at org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.autoLogin(AbstractRememberMeServices.java:137)
	at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:104)
	at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:92)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:218)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:834)

2021-07-16 16:10:09.412  INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository        : remember-me token 획득
Hibernate: 
    select
        rememberme0_.series as series1_1_,
        rememberme0_.last_used as last_use2_1_,
        rememberme0_.token as token3_1_,
        rememberme0_.username as username4_1_ 
    from
        persistent_logins rememberme0_ 
    where
        rememberme0_.series=?
2021-07-16 16:10:09.421  INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository        : remember-me token 획득 tokne 55vHBaBrKjGiA039ZzOH4w==
2021-07-16 16:10:09.441  INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository        : remember-me token 삭제 11
Hibernate: 
    select
        rememberme0_.series as series1_1_,
        rememberme0_.last_used as last_use2_1_,
        rememberme0_.token as token3_1_,
        rememberme0_.username as username4_1_ 
    from
        persistent_logins rememberme0_ 
    where
        rememberme0_.username=?
Hibernate: 
    delete 
    from
        persistent_logins 
    where
        series=?
2021-07-16 16:10:09.492 ERROR 18296 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] 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:113)
	at org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.autoLogin(AbstractRememberMeServices.java:136)
	at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:104)
	at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:92)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:218)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:710)
	at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:459)
	at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:384)
	at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
	at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:398)
	at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:257)
	at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:352)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:177)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:834)

2021-07-16 16:10:09.493 ERROR 18296 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing ErrorPage[errorCode=0, location=/error]

답변 1

0

정수원님의 프로필 이미지
정수원
지식공유자

제가 강의에서 리멤버 미 관련해서 DB 를 사용하는 방식은 몇가지 해결해야 할 이슈가 있어서 강의에서 제외했습니다.

일단 깃헙 소스 공유가 가능할까요?

DB 환경까지 갖추어 테스트하기가 쉽지는 않겠지만 직접 어플리케이션을 구동하지 않고서  답변을 드리기가 어려운 점이 있습니다.

윤지상님의 프로필 이미지
윤지상

작성한 질문수

질문하기