防止PHP中不受信任的来源发生注销操作

时间:2011-03-01 12:17:05

标签: php security xss csrf csrf-protection

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

http://mysite.com/User/Logout

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

有什么想法吗?

6 个答案:

答案 0 :(得分:5)

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

请记住,虽然在这种情况下使用GET不符合RFC,但并不是您需要更改以防止XSRF的所有内容。有关出色的解释,请参阅this answer by ircmaxell

答案 1 :(得分: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>
    

    绝对比什么都好。但我仍然建议使用该表格以获得最佳保护。

  3. 高度建议阅读并关注OWASP CSRF Guidelines以防止CSRF。它会告诉你几乎所有你需要知道的,以及为什么......

答案 2 :(得分:0)

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

答案 3 :(得分:0)

重写为/ logout读取?#NONCE#,#NONCE#是您从请求更改为请求的值。

答案 4 :(得分:0)

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

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

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

答案 5 :(得分: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