• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

Remember-me .CookieTheftException Exception 문의

21.07.16 16:24 작성 조회수 394

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