Spring Security Несоответствие недопустимого токена запоминания (серия/токен). Подразумевает предыдущую атаку кражи файлов cookie

У меня есть приложение GWT, использующее Spring Security3.1.2, работающее в tomcat 7. Я использую UsernamePasswordAuthenticationFilter и PersistentTokenBasedRememberMeServices для сохранения логинов в БД. кроме того, я также использую tomcat PersistentManager для сохранения сеанса в БД. теперь моя проблема заключается в том, что каждый раз, когда я пытаюсь войти в систему, я получаю сообщение Неверный токен запоминания (серия/токен), не соответствующий CookieTheftException (я добавил стек ниже). я попытался удалить сеанс из таблицы tomcat_sessions следующим образом

  1. выключение кота
  2. удалить записи из таблицы tomcat_sessions
  3. начать кот
  4. попробуйте войти в приложение, где я снова получаю CookieTheftException...

я также заметил, что даже после удаления всех записей в таблице tomcat_sessions и когда я перезапускаю tomcat, tomcat_sessions заполняется всем сеансом, который я удалил ранее...

я также удалил все записи в таблице Spring persist_logins и отключил tomcat PersistentManager, но все еще имею ту же проблему...

есть идеи, в чем может быть проблема? Спасибо

SEVERE: Servlet.service() for servlet [springMvcServlet] in context with path [/brate] 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:102)
    at org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.autoLogin(AbstractRememberMeServices.java:115)
    at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:97)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at com.brate.admin.server.servlet.crawler.GoogleBotFilter.doFilter(GoogleBotFilter.java:202)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:695)

person Sameeh Harfoush    schedule 18.11.2013    source источник


Ответы (3)


Просто для того, чтобы мы были на одной странице, я сначала уделю минуту, чтобы объяснить, как я понимаю, что работает этот механизм постоянных токенов.

Начиная с нуля (нет записей в таблице persistent_logins):

При успешном входе: для пользователя будет создан постоянный токен со случайным хешем. Для пользователя создается файл cookie с данными токена. Сеанс создается для пользователя.

Пока у пользователя все еще есть активный сеанс, функция «запомнить меня» не будет вызываться при аутентификации.

После истечения срока действия сеанса пользователя. Функция «Запомнить меня» срабатывает и использует файл cookie для извлечения постоянного токена из базы данных. Если постоянный токен совпадает с маркером из файла cookie, то все довольны, поскольку пользователь проходит аутентификацию, генерируется новый случайный хэш, и постоянный токен обновляется вместе с ним, а также обновляется файл cookie пользователя для последующих запросов.

Но если токен из файла cookie не совпадает с токеном из сохраненного токена, вы получите исключение CookieTheftException. Наиболее распространенная причина несоответствия токенов заключается в том, что 2 или более запросов были запущены в быстрой последовательности, когда первый запрос пройдет, сгенерировав новый хэш для следующих запросов, но второй запрос все еще будет иметь старый токен. это и, таким образом, приводит к исключению.

Чтобы в значительной степени избежать CookieTheftException, убедитесь, что запросы к содержимому вашего веб-приложения (например, изображениям, шрифтам, сценариям и т. д.) не проходят через фильтры аутентификации Springs. Для этого просто добавьте еще одну конфигурацию <http> над вашей обычной конфигурацией безопасности и укажите, что вы не хотите никакой защиты для запросов к вашим ресурсам (используйте соответствующий путь вместо /resources/**):

<http pattern="/resources/**" security="none"/>
<http ... (normal config) ... 

(Информацию о конфигурации Java см. здесь: https://stackoverflow.com/questions/28455507/how-do-i-define-http-security-none-in-javaconfig)

Если вы удалите токен пользователя из базы данных (и срок его сеанса истек), то пользователь выйдет из системы при следующем запросе. Итак, то, что вы говорите о ваших постоянных токенах (в таблице persistent_logins), которые автоматически воссоздаются, имеет очень мало смысла, и я очень сомневаюсь, что это так. Метод PersistentTokenRepository createNewToken(PersistentRememberMeToken token) вызывается только при успешном входе в систему.

Наконец, если вы все еще получаете исключение, полезно прикрепить исходники для PersistentTokenBasedRememberMeServices и поставить точку останова в методе processAutoLoginCookie, чтобы увидеть, какой запрос вызывает CookieTheftException.

Надеюсь, это поможет.

person Markus Coetzee    schedule 18.11.2013
comment
Спасибо, Маркус, я понимаю все, что вы сказали о танце аутентификации/токенов. я буду отлаживать класс PersistentTokenBasedRememberMeServices для более подробной информации. но что меня смущает, так это то, что все работает хорошо, когда я запускаю приложение в режиме разработки GWT, то есть с причала GWT. проблема в том, что когда я компилирую и запускаю приложение в tomcat. вызовет ли tomcat PersistentManager такую ​​​​проблему или это не имеет ничего общего с управлением весенними сеансами? - person Sameeh Harfoush; 19.11.2013
comment
Что касается автоматического создания сеансов, это происходит с таблицей tomcat PersistentManager tomcat_sessions, а не с таблицей Spring persistence_logins. - person Sameeh Harfoush; 19.11.2013
comment
хорошо, вот что я сделал, я отключил tomcat PersistentManager, заменив context.xml и catalina.properties свежими, и внезапно все заработало хорошо ... вы пытались запустить службу «запомнить меня» с помощью PersistentManager раньше? - person Sameeh Harfoush; 19.11.2013
comment
Привет, Самет, хорошо, извини, что я путаю два стола. Я не использовал эту функцию постоянных сеансов от Tomcat, но я думаю, что с вашими оригинальными исключениями cookieTheftExceptions могло произойти то, что существующие токены в persist_logins аутентифицируют пользователя (воссоздавая сеанс) при первом запросе (и, таким образом, сохраняются в tomcat_session) , но второй запрос, который пришел сразу после него, все еще имел старый токен, что вызвало исключение. Вы ранее удаляли все из обеих таблиц (persistent_logins и tomcat_session)? Если так, то я немного в тупике :/ - person Markus Coetzee; 19.11.2013
comment
я попытался удалить tomcat_session, как описано в исходном сообщении, но tomcat продолжает заполнять таблицу между перезапусками сервера. с другой стороны, я смог удалить строки persist_logins. возможно, это вызвало несинхронизированное сопоставление сеанса/токена между tomcat и Spring. в любом случае, я пока отказался от Tomcat PersistentManager... :| спасибо за ваше продолжение :). я опубликую свои выводы, когда я снова работаю над этим. - person Sameeh Harfoush; 19.11.2013
comment
я разместил тему на форуме Spring forum.spring.io/forum/spring-projects/security/ - person Sameeh Harfoush; 20.11.2013
comment
У меня была такая же проблема, пока я полностью не очистил все данные браузера (кеш, файлы cookie и т. д.) и не очистил записи persist_logins. Я думаю, по крайней мере, в моем проекте я менял некоторые настройки, и это вызывало проблемы. С тех пор проблема больше не повторялась. - person Jason; 09.01.2014
comment
@Markus: Мы столкнулись с аналогичной проблемой. Как вы и предложили, даже после того, как мы обеспечим следующее: Чтобы в значительной степени избежать CookieTheftException, убедитесь, что запросы к содержимому вашего веб-приложения (например, изображениям, шрифтам, сценариям и т. д.) не проходят. Фильтры аутентификации Springs. Мы по-прежнему сталкиваемся с проблемой, так как в нашем случае 2 или более остальных вызовов запускаются в быстрой последовательности и используют одно и то же значение файла cookie. Ожидается, что даже в заголовке ответа первых оставшихся вызовов SET COOKIE обновит значение файла cookie RememberMe. Но второй вызов срабатывает до этого. Какие-либо предложения. -Хемант - person hemantvsn; 27.03.2015
comment
Если сохраненный токен совпадает с токеном из файла cookie, то все довольны, поскольку пользователь проходит аутентификацию, генерируется новый случайный хеш — отличный совет. Я провел несколько часов, пытаясь понять, почему функция «запомнить меня» не работает. Я уже проверил заголовок Set-Cookie на наличие нового токена «запомнить меня», и они были очень похожи, но НЕ РАВНЫ. Так что, если вы ломаете голову из-за якобы одинакового токена «запомнить меня», но ваша повторная аутентификация не работает, возможно, они похожи, но не равны, проверьте их еще раз. - person rmpt; 09.09.2018
comment
Я хотел бы поделиться своим примером HttpSecurity JavaConfig, вдохновленным ответом MarkusCoetzee stackoverflow.com/a/52955439/1429387 - person naXa; 23.10.2018

У меня была такая же ошибка, и я заметил, что он пытался автоматически войти в систему каждый запрос, где цепочка безопасности игнорировалась. Вы можете увидеть, какие из них, выполнив

public void configure(WebSecurity web) throws Exception {
    web
        .debug(true)
        .ignoring()
        .antMatchers("/css/**", "/js/**", "/img/**");
}

После этого я замечаю файлы js и файлы css, где, пропуская цепочку безопасности, я удалил эти сопоставления и помню, что начал работать как надо.

public void configure(WebSecurity web) throws Exception {
    web
        .debug(true)
        .ignoring()
        .antMatchers("/img/**");
}
person Johann    schedule 11.04.2014

Недостающей частью моих конфигураций был RememberMeAuthenticationProvider. (http://docs.spring.io/spring-security/site/docs/3.2.2.RELEASE/reference/htmlsingle/#remember-me-impls)

Обратите внимание, что пакет для RememberMeAuthenticationProvider изменился и отличается от документа.

Не забудьте определить один и тот же ключ для PersistentTokenBasedRememberMeServices и RememberMeAuthenticationProvider

Это моя конфигурация:

<s:http auto-config="false"
            use-expressions="true"
            create-session="ifRequired">
        <s:remember-me services-ref="rememberMeServices"
                       authentication-success-handler-ref="rememberMeAuthenticationSuccessHandler"/>
...
</s:http>

 <bean id="rememberMeServices"
          class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
     <constructor-arg index="0" value="${remember.me.key}" />
...
</bean>

<bean id="rememberMeAuthenticationProvider" class=
        "org.springframework.security.authentication.RememberMeAuthenticationProvider">
        <property name="key" value="${remember.me.key}"/>
    </bean>

<s:authentication-manager alias="authenticationManager">
        <s:authentication-provider ref="rememberMeAuthenticationProvider" />
...
    </s:authentication-manager>

Ответ Маркуса Кутзи действительно прояснил для меня ситуацию. Спасибо!

person bentzy    schedule 12.03.2014