Skip to content

Session middleware: responses carrying a session token can be stored by shared caches #297

Description

@allen0099

Problem

When FastAPICacheXSessionMiddleware sends a token (a new session, a sliding renewal, or a regenerated ID) it adds nothing that stops a shared cache from storing it. Vary is only added when the handler touched request.session (middleware.py, if session.accessed), and no Cache-Control is set.

On a @cache(ttl=60, public=True) route, a request that happens to trigger sliding renewal gets:

Cache-Control: public, max-age=60
Vary: (none)
Set-Cookie: session=fa632cf2-...; path=/; Max-Age=1209600; httponly; samesite=lax

A CDN or reverse proxy that stores responses with Set-Cookie will hand that cookie, which is a valid session token, to the next visitors. With header transport the token is in X-Session-Token, which proxies do not treat specially at all. With the default sliding_threshold=0.5 this happens on any request in the second half of a session's TTL.

#168 fixed which header name goes in Vary; it did not cover responses where the session was not accessed but a token is still emitted.

Proposal

Whenever the middleware emits a token (_emit_token) or a clearing cookie:

  • set Cache-Control: private, no-store (overriding a public/max-age value; a token must never be shared), and
  • add Vary for the transport in use (the header name, or Cookie), regardless of session.accessed.

Document the change in SESSION.md. It only affects responses that carry a token, so cacheable responses without one keep their headers.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecuritySecurity vulnerability or hardeningsessionSession management subsystem

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions