7

I'm encountering a (apparently common) problem with browser caches, and my secure pages being accessible via the back button (after user logout.)

Here is my logout.php

<?php
    // 1. Find the session 
    session_start();

    // 2. Unset all the session variables
    $_SESSION = array();

    // 3. Destroy the session cookie
    if(isset($_COOKIE[session_name()])) {
        setcookie(session_name(), '', time()-42000, '/');
    }

    // 4. Destroy the session
    session_destroy();

    redirect_to('index.php?logout=1');
?>

This successfully logs out users on IE7, IE8, Chrome and Firefox--but in Safari, I'm able to press the back button (immediately after logging out) and still see the secure content. If I refresh the secure page, it boots me to the login screen (as it should.)

I've tried using:

<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="-1">

...but it has no effect. Can anyone offer any advice? I've found this article on browser caching, but I have yet to find an answer within it... although I did find:

<?php
 Header("Cache-Control: must-revalidate");

 $offset = 60 * 60 * 24 * 3;
 $ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
 Header($ExpStr);
?>

...which also does not solve the "problem." Hmm.

jlmakes
  • 2,945
  • 1
  • 26
  • 38
  • Browsers are free to cache data and later display it when the user presses the "back" button. That's probably what's happening here, and there's not much you can do about it. – You Feb 11 '11 at 00:43
  • Related: http://stackoverflow.com/questions/64059/is-there-a-way-to-keep-a-page-from-rendering-once-a-person-has-logged-out-but-hit – Pekka Feb 11 '11 at 00:47
  • 1
    Once the content has been delivered, it is no longer secure. –  Feb 11 '11 at 00:49
  • The only thing I can think of is loading the protected data through Ajax. That would kill it in every browser I know at the moment (very annoyingly visible when searching for a user on SO, clicking on the profile, and using the back button to get back to the list), but it's only a question of time until browsers start remembering the DOM in exactly the state it was in when the user left the page – Pekka Feb 11 '11 at 01:01
  • I disagree with You. Think of facebook, when you logout and press back you don't get back to secure content, you are sent to a login page. There must be a way. – joshcartme Feb 24 '11 at 20:23
  • @Loarfatron - You're right... with Safari, Facebook's back button works "properly." I think I read they're using C++ (with some PHP) or something. A Javascript / PHP solution just may not be available at this time... – jlmakes Feb 24 '11 at 21:31

3 Answers3

3

If you can use HTTPS, this combined with a Cache-control: no-cache header will disable the "page cache" (the WebKit term for in-memory/back-forward cache). The downside of this is that it will be disabled for all secure page views, not just after log out. (Source; note they are working on allowing exceptions, it's worth keeping an eye on this.)

If you can depend on JavaScript, attaching an unload event handler will prevent the "page cache". This has the benefit of also allowing you to only break the cache when a "log out" button or link is clicked, by only then attaching the unload event handler. (Source)

Neither of these solutions are ideal, but one of them might be a worthwhile compromise.

eyelidlessness
  • 62,413
  • 11
  • 90
  • 94
1

This would appear to be a webkit/Safari problem. This has been asked before without a definitive answer here - Safari Back button not honouring PHP logout session

Take a look at the links in the answer, I think you'll find your answer in the Unload Event.

Community
  • 1
  • 1
Brent Friar
  • 10,588
  • 2
  • 20
  • 31
  • I disagree with the notion that this is a "problem". When I press the back button, I expect to see the same thing that I saw when originally visiting the page. I'd even go as far as to say that all other browsers are doing this wrong. – You Feb 11 '11 at 00:57
  • It's definitely a problem because it completely defeats the purpose of logging out to begin with. If clicking the logout button does not prevent entry to the secured part of the site, then what does? – Brent Friar Feb 11 '11 at 01:13
  • @Brent: There is no concept of "entry" or "exit" in HTTP. It's all just requesting resources from URLs. No state is maintained. Clicking "log out" should indeed log you out. You can still click the back button to re-view the page you just logged out of, IF your browser has cached it (which it shouldn't have if it respects HTTP response cache headers). However, that does not mean that you are still logged in, or that any of the links on the page will still work. This is why sensitive sites (like banks) always implore you to close your browser after logging out. – alexantd Feb 11 '11 at 01:26
  • Actually, after reviewing exactly how no-cache is supposed to work it does make sense why it works like this. It would appear that there is no good answer at this point. This has a pretty good write up the back button issue - http://my.opera.com/yngve/blog/2007/02/27/introducing-cache-contexts-or-why-the – Brent Friar Feb 11 '11 at 01:43
  • @Brent - It boots you to login when you refresh. Do you think it'd even be worth implementing a forced refresh on member-only pages? I don't think any of the data is that sensitive... I just wouldn't want a member to go back, perform edits, try and save and then lose those edites when booted back to login. Stupid I know, but I have account for people doing stupid things lol. – jlmakes Feb 11 '11 at 05:14
  • @Julian I know what you mean, I was speaking in general security terms. While nothing would work if clicked, account numbers or other sensitive material could be compromised in some situations (no necessarily yours). If it's really important you can add the must-revalidate directive. The trade off is that it slows browsing somewhat. I think the better solution would be to put a big fat warning on the logout landing page no to hit the back button and to close the browser window with a new login form below that. – Brent Friar Feb 11 '11 at 13:44
0

Part of the problem is that you're setting an Expires header in the future. Browsers use the Expires header as an indicator of how long something should stay in cache. Try this:

$offset = 60 * 60 * 24 * 3;
$ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() - $offset) . " GMT";
Header($ExpStr);

This will set an expires header in the past, and force the browser to re-request the page every time.

Chris Henry
  • 11,914
  • 3
  • 30
  • 31
  • I tried `header("Expires: Mon, 23 Jul 1997 05:00:00 GMT");` but to no avail; Safari still allows access to the page. – jlmakes Feb 11 '11 at 02:36