Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent Logout Action from Happening from Untrusted Sources in PHP

I have an action in my site:

http://mysite.com/User/Logout

This will log the current user out of his/her session. Since this is a simple GET request, a malicious user could either create links to this page or even put this link in an image's src attribute that would force users to get logged out. I would still like to maintain the simplicity of the logout link without having to go too far, but at the same time I would like to be able to prevent the above scenario from occurring.

Any ideas?

like image 281
Doctor Blue Avatar asked Mar 01 '11 12:03

Doctor Blue


2 Answers

Well, there are a few options that you can do to help secure against CSRF attacks:

  1. Use a form and a random token. So instead of having a "link", use a random token that's set in the session into a form

    <form action="/User/logout" method="post">
        <submit name="logout" value="Logout" />
        <input type="hidden" name="token" value="<?php echo getSessionToken(); ?>" />
    </form>
    

    Note that POST is best for this type of action, but you could change the form to a GET without too much trouble.

    Then in php, just do:

    if (getSessionToken(true) != $_POST['token']) {
        die('CSRF!');
    }
    

    Note that getSessionToken should work something like this:

    function getSessionToken($reset = false) {
        if (!isset($_SESSION['random_token'])) {
            $_SESSION['random_token'] = sha1(uniqid(mt_rand(), true));
        }
        $token = $_SESSION['random_token'];
        if ($reset) {
            unset($_SESSION['random_token']);
        }
        return $token;
    }
    

    Also note that whenever you fetch the token to check it, you should reset it to something new (which is what this does). This prevents replay attacks where an attacker detects the token on submission and resubmits the value.

  2. If you must use a link, then embed the token in the link. But note that this is more susceptible to attack since there's a chance the user might copy and paste the link to someone else. As long as it's a self-resetting token, there shouldn't be much issue with multiple tabs. But realize that it's not optimum:

    <a href="/User/logout?token=<?php echo getSessionToken(); ?>">Logout</a>
    

    It's absolutely better than nothing. But I would still suggest using the form for the best protection.

I would highly suggest reading and following the OWASP CSRF Guidelines for preventing CSRF. It will tell you just about all you need to know, and why...

like image 189
ircmaxell Avatar answered Sep 28 '22 04:09

ircmaxell


If you log people out using GET requests (or do anything more important than that using GET requests, for that matter) then your website will be vulnerable to cross-site request forgery attacks. You should use POST to log out people. GET is only for idempotent actions, see RFC 2616 section 9.1.

Keep in mind that while using GET in this case is not compliant with the RFC, it is not everything that you need to change to prevent the XSRF. See this answer by ircmaxell for an excellent explanation.

like image 20
Zed Avatar answered Sep 28 '22 03:09

Zed