开发者

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开发者_C百科 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?


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...


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.


Without changing the HTTP method you could add a unique id to the users session and append that to the logout link. If a logout action is performed and the two id's match the logout is valid. Else it's not!


Rewrite to read like/Logout?#NONCE#, #NONCE# being a value you change from request to request.


You're going to have to require some sort of validator to be passed to the logout page. And it must be soething that's unique to the session and difficult to guess. Now, if only there were a suitable value.....oh yes, the session identifier.

Note that you should be using cookies for session management, and you should be setting the http only flag on the session cookie - so you'll need to populate the link from PHP (or copy the session id into a javascript readable cookie).

<?php
   session_start();
   if ($_GET['logout_valid']!==session_id()) {
       // handle invalid logout request
       exit;
   } else {
       $_SESSION=array();
       session_destroy();
   }


I guess I am late to the party, but, here is how I handle it:

<?php

session_start();

function logoutButton($name = 'logout', $action = '/User/logout'){
$random_token = md5(uniq_id());
$_SESSION['csrf'] = $random_token;
$form = '<form ><input type="hidden" value="'. $random_token .'" name="' .$name. '"><input type="button" value="logout"><</form>';
return $form;
}

public static isValidRequest($name = 'logout'){
if(isset($_POST[$name]) && $_POST[$name] === $_SESSION['csrf']){
    return true;
}
return false;
}

}
?>

to display a logout button

echo logoutButton();

To securely logout a user

if(isValidRequest()){
    //logout
}

Hope it s helpful to someone.

edit: Here is a class I created https://github.com/sahithvibudhi/PHP-CSRF-Protection-class

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜