Skip to content

RememberMe refresh can leave oudated token which leads to broken functionality #54192

@heiglandreas

Description

@heiglandreas

Symfony version(s) affected

6.3.11

Due to the way the code is written this still exists in 7.1

Description

Currently when a user encounters a problem during login via RememberMe functionality and the browser does not receive the new RememberMe token and the SessionCookie that same user can still log in when the old RememberMe token is cached.

With the next request they will again send the old RememberMe token and no Cookie so again a login will happen via the cached RememberMe token. Now the user will receive a SessionCookie and is now logged back into the applicaten.

But when the second login happened within 60 seconds from the first one, the user will - due to the change from #47488 - not receive the current RememberMe token. So the RememberMe Cookie will still contain the old token.

When the users session expires the RememberMe functionality should again kick in. But now the user still has the "old" token. When the old token is still in the token-cache the login will work and the user will now have an up-to-date rememberMe token.

But usually at that point the token cache has dropped the old token so that the token is considered to be stale and a CookieTheftException is raised.

What sounds like a really exotic edge-case causes about 3000 CookieTheftExceptions per day in our application. As the root cause can be any network interruption that causes the response of a RememberMe authentication to not reach the client it might actually trigger an immediate reload of the resource so that the second login actually happens rather often within the 60 second timeframe.

From #47488:

2 requests come by at the same time with tokenA:

* the one that wins the race persists and sends back tokenB

* the other one accepts tokenA but doesn't send any cookie back, aka tokenB from req 1 stays in the cookie jar.

Unless I missed something, this still fixes the situation that @heiglandreas describes in #46760 while preventing a needless disclosure of the currently valid token to the 2nd request.

The problem happens when the request that wins the race doesn't actually return to the client and then tokenB is lost in the void. The other request will be accepted with tokenA but the chain of RememberMe tokens is broken and the following authentication has to happen via other means - which defeats the purpose of having a RememberMe functionality.

How to reproduce

  • Log into an application using the RememberMe functionality and activate the RememberMe functionlaity for future logins
  • Make sure you have xdebug running and can stop a request at will
  • Delete the session-cookie so that the next request will trigger a RememberMe authentication
  • trigger a debugging request to an endpoint that will timeout. The important part is the timeout, not XDebug per se. It is just a way to slow down handling of the request until the client or the application server (like nginx) will timeout.
  • This will have triggered a RememberMe login and therefore we have the old RememberMe token in the cache and a new one in the database. As the connection timed out the client has not received the new token or a new session-ID
  • Within 60 seconds (this timing is important!) trigger another request without debugging (as above the debugging is irrelevant. The main thing is that this request does not time out). The request will submit the old token and cause a RememberMe authentication again. This time the old token is verified against the one in cache. Note that the response does not contain setting a new RememberMe token, only a new session token!
  • Now remove the old RememberMe token from the cache
  • Also remove the session cookie from the browser.
  • Now trigger the request again. The RememberMe functionality will not work and you will have to log in via alternative means.

Possible Solution

  • Always return the current RememberMe token when logging in via cached Rememberme token.
  • Return the current RememberMe token always when some additional information match the information from the creation/update of the token.

The new token will in any case be returned after the 60 second interval. So depending on how long the old token is cached (which can be much longer than 60 seconds depending on the implementation) there is no carefully planned attack needed but one just needs to wait for more than 60 seconds to authenticate again with the old token.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy