5

我在我的网站上有一个动作:

http://mysite.com/User/Logout

这将使当前用户退出他/她的会话。由于这是一个简单的 GET 请求,恶意用户可以创建指向此页面的链接,甚至可以将此链接放入图像的src属性中,从而强制用户退出。我仍然希望保持注销链接的简单性而不必走得太远,但同时我希望能够防止上述情况发生。

有任何想法吗?

4

6 回答 6

5

如果您使用 GET 请求将人们注销(或做任何比使用 GET 请求更重要的事情),那么您的网站将容易受到跨站点请求伪造攻击。您应该使用 POST 注销人员。GET 仅用于幂等操作,请参阅RFC 2616 第 9.1 节

请记住,虽然在这种情况下使用 GET 不符合 RFC,但它并不是您需要更改以防止 XSRF 的所有内容。请参阅ircmaxell的这个答案以获得很好的解释。

于 2011-03-01T12:29:15.553 回答
5

好吧,您可以采取一些措施来帮助抵御 CSRF 攻击:

  1. 使用表格和随机标记。因此,不要使用“链接”,而是使用在会话中设置为表单的随机令牌

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

    请注意,POST 最适合这种类型的操作,但您可以将表单更改为 GET 而不会有太多麻烦。

    然后在 php 中,只需执行以下操作:

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

    请注意,getSessionToken应该像这样工作:

    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;
    }
    

    另请注意,每当您获取令牌进行检查时,都应将其重置为新的东西(这就是这样做的)。这可以防止攻击者在提交时检测到令牌并重新提交值的重放攻击。

  2. 如果您必须使用链接,则将令牌嵌入链接中。但请注意,这更容易受到攻击,因为用户可能会将链接复制并粘贴给其他人。只要它是一个自重置令牌,多个选项卡应该不会有太大问题。但要意识到这不是最佳的:

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

    这绝对比没有好。但我仍然建议使用表格以获得最佳保护。

强烈建议阅读并遵循OWASP CSRF预防 CSRF 指南。它会告诉你几乎所有你需要知道的,以及为什么......

于 2011-03-01T13:30:53.437 回答
0

在不更改 HTTP 方法的情况下,您可以向用户会话添加唯一 id 并将其附加到注销链接。如果执行注销操作并且两个 id 匹配,则注销有效。否则不是!

于 2011-03-01T12:24:52.217 回答
0

Rewrite to read like/Logout?#NONCE#, #NONCE# 是您从请求到请求更改的值。

于 2011-03-01T12:28:19.873 回答
0

您将不得不要求将某种验证器传递到注销页面。并且它必须是会话独有的并且难以猜测的东西。现在,如果只有一个合适的值.....哦,是的,会话标识符。

请注意,您应该使用 cookie 进行会话管理,并且应该在会话 cookie 上设置 http only 标志 - 因此您需要从 PHP 填充链接(或将会话ID复制到 javascript 可读 cookie 中)。

<?php
   session_start();
   if ($_GET['logout_valid']!==session_id()) {
       // handle invalid logout request
       exit;
   } else {
       $_SESSION=array();
       session_destroy();
   }
于 2011-03-01T13:15:01.423 回答
0

我想我迟到了,但是,我是这样处理的:

<?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;
}

}
?>

显示注销按钮

echo logoutButton();

安全地注销用户

if(isValidRequest()){
    //logout
}

希望它对某人有帮助。

编辑:这是我创建的一个类https://github.com/sahithvibudhi/PHP-CSRF-Protection-class

于 2017-04-07T14:09:26.710 回答