Using the back button after logging out shows you pages from the authenticated user's session

Created on 9 February 2013, almost 12 years ago
Updated 5 April 2024, 8 months ago

Problem / Motivation

Screen recording: https://drive.google.com/file/d/1Psq-aeG_j7XH3BTj_jl2eMz8ekb32vqy/view?u.... Browser: Firefox.

Originally reported as a security issue by David Rothstein, but making it into a public issue as the security team considers this non-critical and thus can be fixed in the public queue.

=====
Testing with Firefox, if you log out of a Drupal site and then hit the back button, you can see pages from the authenticated user's previous session.

This could be a problem on public computers, if the authenticated user had permission to see content protected by node access (or similar).

Variations of this have been reported in the public issue queue in many places. For example:

We might say it's OK to discuss in public (and it certainly would be hard to find and unpublish all the existing issues now anyway) but I thought it might be useful to discuss here first.

As far as I can tell, the simplest way to fix this is to add the "no-store" header to all pages viewed by an authenticated user; however, Drupal used to do this but it was removed a long time ago (see http://drupal.org/node/109941) because it was causing all sorts of annoyances when an authenticated user tried to use the back button while still logged in. So, it's possible there isn't really a great solution here.

Security Note

Back and refresh attack

Screen recording: https://drive.google.com/file/d/1Psq-aeG_j7XH3BTj_jl2eMz8ekb32vqy/view?u.... Browser: Firefox.

There is a potential security concern here: imagine a user on a public computer. They log in to Drupal, go to pages that only an authenticated user should see, then logout. Unless the browser session was closed (the in-browser caches cleared), then someone else could come to that computer and click the back button to see those pages.

While the risk applies to anything you can see on the screen, it can also apply to anything in markup, notably a password field. See https://resources.infosecinstitute.com/browser-based-vulnerabilities-in-... for a generic description of this approach. The example would be someone attempts to login, it fails, and their password is still in the markup. In my testing, I did not see this issue with Drupal 8 because on a failed password attempt the password is cleared out (i.e. its not sent back to the browser). But, the principle of this approach could apply to other fields. If webforms module is used to submit important information, this issue could apply.

On Firefox, you can close the tab or close the browser (quit the browser application), then open the application again and be able to go back in history. In this scenario, the browser's setting is to "Open up previous tabs".

The user can visit multiple previous pages, not just the most recent.

Browser disk cache

Separately, but related, there is a concern about the browser storing these caches on disk. If those caches are not cleaned up, then anyone with access to that disk can access those cached pages.

Examples of this Attack

Steps to reproduce

1. Login to Drupal
2. Go to a page
3. Logout
4. Note you are redirected to the home page
5. Click the browser's "Back" button
6. Note you are now at the page from Step 2 and you see the Drupal admin toolbar (which should only show if you're authenticated)

This issue can be observed in Chrome and Firefox. With Chrome, if you disable cache using browser tools the issue is not observed. With Firefox, if you disable cache using browser tools the issue is still observed.

The issue persists even if you close the tab or quit the browser (tested in Firefox).

The user can click "Back" multiple times to see even older cached pages.

Proposed Resolution

Allow the user to use the back button, but change its behavior based on authenticated status. There are two basic scenarios:

Scenario 1: Logged out to logged in

1. Go to a page
2. Login to Drupal
3. Click the browser's "Back" button
4. Go to the page from Step 1, but you now see the "logged in" version of the page

Scenario 2: Logged in to logged out

1. Login to Drupal
2. Go to a page
3. Logout
4. Click the browser's "Back" button
5. Go to the page from Step 2, but you now see the "logged out" version of the page

The details on how to achieve this are TBD.

Potential Approaches

Here are some approaches discussed, it's uncertain which of these work. Please update this ticket to verify which do.

Option 1: JavaScript History API

See https://www.drupal.org/project/logout_redirect

Option 2: JavaScript window.onpageshow

See https://gomakethings.com/fixing-safaris-back-button-browser-cache-issue-...

Option 3: Cache-Control no-store

See 🐛 Incorrect Cache-Control headers for authenticated users Postponed

Option 4: Clear-Site-Data: "cache"

See https://www.fastly.com/blog/clearing-cache-browser
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data

Reference Material

🐛 Bug report
Status

Needs work

Version

11.0 🔥

Component
Base 

Last updated 43 minutes ago

Created by

🇳🇱Netherlands dokumori Utrecht

Live updates comments and jobs are added and updated live.
  • Security improvements

    It makes Drupal less vulnerable to abuse or misuse. Note, this is the preferred tag, though the Security tag has a large body of issues tagged to it. Do NOT publicly disclose security vulnerabilities; contact the security team instead. Anyone (whether security team or not) can apply this tag to security improvements that do not directly present a vulnerability e.g. hardening an API to add filtering to reduce a common mistake in contributed modules.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇨🇭Switzerland znerol

    OWASP has a page in the WSTG about this topic. Their recommendation:

    The Back button can be stopped from showing sensitive data. This can be done by:

    • Delivering the page over HTTPS.
    • Setting Cache-Control: must-revalidate

    This is basically what Drupal is doing already. Except that there are some additional directives on authenticated pages (Cache-Control: must-revalidate, no-cache, private). I wouldn't expect that the extra directives no-cache and private would reverse the effect of must-revalidate. So I looked at other response headers relevant to browser caching.

    Turns out that we are missing Vary: Cookie on authenticated responses. The culprit is FinishResponseSubscriber::setResponseNotCacheable(). The comment in this method says:

        // There is no point in sending along headers necessary for cache
        // revalidation, if caching by proxies and browsers is denied in the first
        // place. Therefore remove ETag, Last-Modified and Vary in that case.
    

    There is only one situation where this behavior would be correct: On a selected route which is delivered with Cache-Control: no-store in all cases (independently whether a session is open or not).

    In all other situations, the Vary: Cookie header must be on every response. No matter whether a user is logged in or not or a session is open or not.

  • Assigned to znerol
  • @znerol opened merge request.
  • @znerol opened merge request.
  • Issue was unassigned.
  • Status changed to Needs review almost 2 years ago
  • 🇨🇭Switzerland znerol

    MR !3505 adds Vary: Cookie to every response. Obviously needs manual browser testing.

  • Status changed to Needs work almost 2 years ago
  • 🇨🇭Switzerland znerol

    MR !3505 doesn't seem to fix the problem. Interestingly this wasn't an issue on the previous build of the site I am mainly working on. I get a 403 (i.e., the expected behavior) with the following testing scenario in Firefox:

    1. GET /
    2. Log in -> 302 to /
    3. Navigate to profile form (/user//edit)
    4. Logout -> 302 to /
    5. Hit browser back button -> 403

    The legacy site was based on Drupal 7 and Authcache. Authcache encourages the browser to cache pages even for authenticated users. However, it also ensures that the ETag is different for each variant of a page.

    I think that when Authcache is active, the browser is replacing the cached frontpage in step 2 (after login), and the cache is replaced again in step 4 (after logout). My hunch is that a cache replacement (in contrast to a cache insert) invalidates previous history and as a result the browser attempts to refetch the user page when the back button is hit.

    Pure speculation though, more testing is clearly necessary. Also I am a bit disappointed by the OWASP page linked in #39. It doesn't seem to cover the full problem.

  • 🇮🇳India Pemson18 Goa

    see https://www.drupal.org/project/drupal/issues/3130912 🐛 Incorrect Cache-Control headers for authenticated users Postponed

  • 🇫🇮Finland sokru

    Should we consider Option 3:Cache-Control: no-store? On linked issue 🐛 Incorrect Cache-Control headers for authenticated users Postponed there's patches to implement it with test coverage. OWASP recommends the approach also on its FAQ page https://owasp.org/www-community/OWASP_Application_Security_FAQ#how-do-i-...

    Twitter.com and Google seems to rely on Cache-Control: no-store header on authenticated services.

    Fastly article from 2014 states about Vary: Cookie: "Cookie is probably one of the most unique request headers, and is therefore very bad."

  • 🇫🇮Finland sokru

    I tested @znerol's MR !3505 with DDEV, it works only with HTTPS enabled, like mentioned on OWASP documentation. Tested with Firefox, Chrome, Edge. Unfortunately on Safari the back button showed the cached content.

    Wrote on 🐛 Incorrect Cache-Control headers for authenticated users Postponed that we should implement the Cache Control header change on that issue. It will partially fix this issue. On Safari there's a bug https://discussions.apple.com/thread/251817133 and I hope we could narrow down this issue just for Safari.

  • 🇫🇮Finland sokru

    sokru changed the visibility of the branch 1912514-fix-vary-2 to hidden.

Production build 0.71.5 2024