26
votes

I am new to Laravel 5 and trying to make a simple authentication page. My problem is i can logout properly after i click to logout link but if i click to back button of the browser, still able to see the content of the page which actually should not be seen with respect to my auth middleware process. I read i can prevent this by disabling caching but don't think it is the best way to do this so how can i make this in a better way ? Simply my logout route is

Route::get('logout', array('uses' => 'LoginController@logout'));

Logout function is:

public function logout() {
        Auth::logout(); // logout user
        Session::flush();
        Redirect::back();
        return Redirect::to('pages/login'); //redirect back to login
}
10
can you show your code for logout and not only the route - xenish
if you want to clear cache have you tried Cache::flush() - xenish
@xenish check the edited question please, i have put it - Tartar
This not an issue at all. Like @Wader mentioned below its just browser cached page. To verify this click back button and then try accessing pages the are protected - Emeka Mbah
agree with @Digitlimit - xenish

10 Answers

48
votes

When the user clicks the back button they're not actually logged in, its just the browser rendering what it has cached from previous page views. The user won't be able to navigate or interact with anything that requires them to be logged in because, to your application on the server, they're not authenticated.

When the user clicks the back button you have no control over that as it doesn't make a request to the server.

Using the back button, the only content they'll be able to view is that what they have already visited whilst logged in. If they try to access anything new, they'll make a new request to your application, your middleware will trigger and redirect them to the login page.

I guess if you really wanted to stop this behavior you could use some JavaScript and such to send an ajax request and check if the user is logged in that way, but quite useless from a security point of view.

61
votes

Create a middleware using artisan:

php artisan make:middleware RevalidateBackHistory

Within RevalidateBackHistory middleware, we set the header to no-cache and revalidate:

<?php
namespace App\Http\Middleware;
use Closure;
class RevalidateBackHistory
{
    /**
    * Handle an incoming request.
    *
    * @param \Illuminate\Http\Request $request
    * @param \Closure $next
    * @return mixed
    */
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        return $response->header('Cache-Control','nocache, no-store, max-age=0, must-revalidate')
            ->header('Pragma','no-cache')
            ->header('Expires','Fri, 01 Jan 1990 00:00:00 GMT');
    }
}

Update the application’s route middleware in Kernel.php:

protected $routeMiddleware = [
    .
    .
    'revalidate' => \App\Http\Middleware\RevalidateBackHistory::class,
    .
    .
];

And that’s all! So basically you just need to call revalidate middleware for routes which require user authentication.

22
votes

Step 1 : create one middleware using following command:

php artisan make:middleware PreventBackHistory

Step 2:

replace content of PreventBackHistory.php with following content:

<?php

namespace App\Http\Middleware;

use Closure;

class PreventBackHistory
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        return $response->header('Cache-Control','no-cache, no-store, max-age=0, must-revalidate')
            ->header('Pragma','no-cache')
            ->header('Expires','Sun, 02 Jan 1990 00:00:00 GMT');
    }
}

step 3: register middleware in kernal.php

'preventBackHistory' => \App\Http\Middleware\PreventBackHistory::class,

And good to go :)

11
votes

A method I have used is to simply redirect to the previous page after logout. So long as the previous page was secured, the auth middleware will kick in and redirect you back to the login page. Now when you click the back button the previous page is no longer cached and you just get the login page again.

Original discussion: https://laracasts.com/discuss/channels/requests/back-button-browser

public function logout() {
        Auth::logout(); // logout user
        return redirect(\URL::previous());
}
2
votes

Yeah its just a browser behavior, not any issue from laravel side but this could be a security issue. Here is how i solved it,

  1. Create new middleware

php artisan make: middleware PreventBackHistory

  1. Replace middleware function handle
    $response = $next($request);
    $response->headers->set('Cache-Control','nocache, no-store, max-age=0, must-revalidate');
    $response->headers->set('Pragma','no-cache');
    $response->headers->set('Expires','Sun, 02 Jan 1990 00:00:00 GMT');
    return $response;
  1. Include path in Kernal

'prevent-back-history' => \App\Http\Middleware\PreventBackHistory::class

  1. Update Routes

Route::group(['middleware' => ['prevent-back-history','otherMiddlewares']]

It will work for you!

0
votes

You can overwrite logout method in your AuthenticatesUsers trait as:

public function logout(Request $request)
    {
        $this->guard()->logout();
        $request->session()->invalidate();
        return $this->loggedOut($request) ?: redirect()->back();
    }
0
votes

Using this <a href={{$_SERVER['HTTP_REFERER']}}>back</a> comes handy.

0
votes

This question was considered resolved, but I'd like to put the solution I found and worked for me, since as explained by Jeff Adams in the comment below the selected answer, someone else might be able to see sensible information on the pages the user visited before logging out, big security concern in my opinion.

I am using apache so I added the following headers to my public/.htaccess:

  • Header set Cache-Control "no-cache, no-store, must-revalidate"
  • Header set Pragma "no-cache"
  • Header set Expires 0

A more generic way would be to add the meta tags to your HTML:

  • <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
  • <meta http-equiv="Pragma" content="no-cache" />
  • <meta http-equiv="Expires" content="0" />

You can find what best fits your application here: https://cristian.sulea.net/blog/disable-browser-caching-with-meta-html-tags/

0
votes

I know its an old question,

but there can be another approach as well. Using the Middleware and solve the issue is logical but it will remove the cache of browser and that will have bad impact on the performance side.

So another approach is just to use a localstorage variable while login , set it as 1 then on the logout set it as 0 , On each page (the main layout is going to extend all our pages) check the localstorage value is 0 or not if its 0 redirect to login page.

In this way once user logout and press back button , the previous page will load and check the localstorage value and it again redirect back to login page. If you can put the checking script in top section of the page it will avoid the loading of that page as well.

 if(localStorage.getItem('loginstatus') == 0){
     document.location.href = "{{route('login')}}";
 }
-1
votes

Try redirecting to a protected route with auth middleware:

return redirect('home');

so it will force redirect to the login page & the back button will not show the previous page