Closed haizz closed 2 months ago
Thanks for reporting this, we'll look into it
I would like to understand why Vert.x uses the headers end signal to trigger session flushing. I looked into two other Java libraries and they use the completion of the HTTP server response:
@pmlopes @vietj do you know why Vert.x behaves differently? I searched the git history and it has been like this since the original commit in this repository.
If there is no particular reason, perhaps we could move change the trigger. Beyond fixing this issue, I believe there are good reasons why a user may want to store data in the session as they generate the content (if the response is chunked).
For the record, @vietj can't think about a particular reason why Vert.x uses the headers end handler as a trigger for flushing the session.
In the meantime, I did some research about CSRF (admittedly not my area of expertise) and mitigation as well as the reason why #2447 was solved with #2500
OWASP describes CSRF attacks as well as how to prevent them.
Vert.x implements the Signed Double-Submit Cookie pattern, with a per-session token.
In this case, the session has a new token that is never sent to the user, because GET requests do not send a cookie with the new value. Therefore, the client cannot send any POST requests again, until the session is recreated (e.g. logout/login).
The solution implemented in #2500, as explained by @haizz above, was to make the CSRFHandler update the session only when Vert.x has successfully sent the response to the wire. But, since the session has been flushed at a previous stage, this only works when using a single server or sticky sessions, not clustered sessions.
Also, it does not prevent the client from being "trapped" if an intermediate proxy fails to send the response to the client.
Considering the points above, changing the session persistence trigger seems like descending into the rabbit hole to me.
Failures will happen, and when they do:
So I will send a PR asap that does this and reverts the modification introduced in #2500 (i.e. store new tokens in the session immediately instead of waiting for the response to be sent)
It's not necessary to change the session flush trigger.
cc @vietj @pmlopes @chrispatmore
Fixed by 5b0008b5d
Version
4.5.7
Context
Root cause seems to be in #2500 (#2447, #2460)
CSRFHandlerImpl updates the session with End Handler:
But SessionHandlerImpl flushes the session with HeadersEnd Handler
So SessionHandlerImpl flushes the session on headers end, and then CSRFHandlerImpl updates the already flushed session, and no changes end up being saved in the session store.
Tests work because LocalSessionStore store raw session objects in the map. So when you update the session object, no flush is needed: next time you retrieve updated session object from the store. It won't work when sessions are serialized/deserialized in the store.