Skip to content

fix(session): Prevent stale requests from replacing a regenerated session - #65928

Merged
DerDreschner merged 1 commit into
masterfrom
fix/stale-session-ids
Nov 4, 2026
Merged

DerDreschner merged 1 commit into
masterfrom
fix/stale-session-ids

Conversation

@DerDreschner

Copy link
Copy Markdown
Member

Summary

When the session id is being regenerated (for example when you unlock a public share while a request from another tab is already on its way), the session can flap back to the old one due to stale requests. When PHP receives a stale request with the previous session id, it starts a new session with the old session id and sets a new cookie with the old session id. The browser is pushed back onto the old session and loses everything the regenerating request did, which leads to intermittent 401 errors - for a password-protected public share, the file list fails with a 401 on PROPFIND /public.php/dav/files/<token>/.

To fix the issue, I no longer delete the old session: it keeps a marker that its id was replaced. A request that still arrives on that id gets an empty session and, for a grace period of 60 seconds, no session cookie at all, so it can no longer replace the id the browser just stored. After the grace period it gets a fresh session with a cookie as usual. Internal::reopen() now starts the session without cookies for the same reason - until now it re-emitted the cookie on every late session write.

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

@DerDreschner DerDreschner self-assigned this Oct 26, 2026
@DerDreschner
DerDreschner requested a review from a team as a code owner October 26, 2026 13:45
@DerDreschner
DerDreschner requested review from provokateurin, salmart-dev and sorbaugh and a balanced review from Copilot and removed request for a team October 26, 2026 13:45
@DerDreschner

Copy link
Copy Markdown
Member Author

/backport to stable35

@DerDreschner

Copy link
Copy Markdown
Member Author

/backport to stable34

@DerDreschner

Copy link
Copy Markdown
Member Author

/backport to stable33

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

@DerDreschner
DerDreschner force-pushed the fix/stale-session-ids branch from d94241c to 783eb52 Compare October 27, 2026 07:04
@DerDreschner
DerDreschner requested a balanced review from Copilot October 27, 2026 07:04

This comment was marked as off-topic.

…sion

Regenerating the session id - on login, on unlocking a public share, on a
remember-me login - leaves the requests that are already on their way with
the previous session cookie. PHP starts a session for that id again and
sends it back in a Set-Cookie header, so the id the browser had just stored
is overwritten and everything the regenerating request did is lost. For a
logged-in user who unlocks a password-protected public share this shows up
as a 401 on PROPFIND /public.php/dav/files/<token>/.

Mark the old session as superseded instead of deleting it, and move the
requests that still arrive on it to an empty session. Within a grace period
of 60 seconds they get no session cookie at all, so they can no longer
replace the regenerated id the browser holds. reopen() does the same and
only sends a cookie when the id it was given is gone for good.

Assisted-by: ClaudeCode:claude-opus-5
Signed-off-by: David Dreschner <david.dreschner@nextcloud.com>
@DerDreschner
DerDreschner force-pushed the fix/stale-session-ids branch from 783eb52 to 25c1ba3 Compare October 27, 2026 08:01

@ChristophWurst ChristophWurst left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a good approach for the tricky problem with the old session cookies overwriting the new ones 👍

Nit: I see some time() calls in prod and test code, which can make the tests fragile. There is a time factory to mock it deterministically.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should use time factory

@DerDreschner
DerDreschner merged commit 6b512d9 into master Nov 4, 2026
181 of 183 checks passed
@DerDreschner
DerDreschner deleted the fix/stale-session-ids branch November 4, 2026 14:08
@backportbot

backportbot Bot commented Nov 4, 2026

Copy link
Copy Markdown

The backport to stable33 failed. Please do this backport manually.

# Switch to the target branch and update it
git checkout stable33
git pull origin stable33

# Create the new backport branch
git checkout -b backport/65928/stable33

# Cherry pick the change from the commit sha1 of the change against the default branch
# This might cause conflicts, resolve them
git cherry-pick 25c1ba3a

# Push the cherry pick commit to the remote repository and open a pull request
git push origin backport/65928/stable33

Error: Failed to check for changes with origin/stable33: No changes found in backport branch


Learn more about backports at https://docs.nextcloud.com/server/stable/go.php?to=developer-backports.

@backportbot

backportbot Bot commented Nov 4, 2026

Copy link
Copy Markdown

The backport to stable34 failed. Please do this backport manually.

# Switch to the target branch and update it
git checkout stable34
git pull origin stable34

# Create the new backport branch
git checkout -b backport/65928/stable34

# Cherry pick the change from the commit sha1 of the change against the default branch
# This might cause conflicts, resolve them
git cherry-pick 25c1ba3a

# Push the cherry pick commit to the remote repository and open a pull request
git push origin backport/65928/stable34

Error: Failed to check for changes with origin/stable34: No changes found in backport branch


Learn more about backports at https://docs.nextcloud.com/server/stable/go.php?to=developer-backports.

@DerDreschner

Copy link
Copy Markdown
Member Author

Time factory fix will come in a new PR

@Voltra

Voltra commented Nov 4, 2026

Copy link
Copy Markdown

I tried to apply the patch in production earlier today to see if it fixed #64659 and it didn't seem to have an effect on that

@DerDreschner

Copy link
Copy Markdown
Member Author

I tried to apply the patch in production earlier today to see if it fixed #64659 and it didn't seem to have an effect on that

That's why it's only listed as "related to". The symptoms are the same for multiple session bugs. The ticket you mention is only one of them. I try to fix them one-by-one (see #65959 and another one that is still in the making).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants