我在我的网站上有一个动作:
http://mysite.com/User/Logout
这将使当前用户退出他/她的会话。由于这是一个简单的 GET 请求,恶意用户可以创建指向此页面的链接,甚至可以将此链接放入图像的src
属性中,从而强制用户退出。我仍然希望保持注销链接的简单性而不必走得太远,但同时我希望能够防止上述情况发生。
有任何想法吗?
我在我的网站上有一个动作:
http://mysite.com/User/Logout
这将使当前用户退出他/她的会话。由于这是一个简单的 GET 请求,恶意用户可以创建指向此页面的链接,甚至可以将此链接放入图像的src
属性中,从而强制用户退出。我仍然希望保持注销链接的简单性而不必走得太远,但同时我希望能够防止上述情况发生。
有任何想法吗?
如果您使用 GET 请求将人们注销(或做任何比使用 GET 请求更重要的事情),那么您的网站将容易受到跨站点请求伪造攻击。您应该使用 POST 注销人员。GET 仅用于幂等操作,请参阅RFC 2616 第 9.1 节。
请记住,虽然在这种情况下使用 GET 不符合 RFC,但它并不是您需要更改以防止 XSRF 的所有内容。请参阅ircmaxell的这个答案以获得很好的解释。
好吧,您可以采取一些措施来帮助抵御 CSRF 攻击:
使用表格和随机标记。因此,不要使用“链接”,而是使用在会话中设置为表单的随机令牌
<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;
}
另请注意,每当您获取令牌进行检查时,都应将其重置为新的东西(这就是这样做的)。这可以防止攻击者在提交时检测到令牌并重新提交值的重放攻击。
如果您必须使用链接,则将令牌嵌入链接中。但请注意,这更容易受到攻击,因为用户可能会将链接复制并粘贴给其他人。只要它是一个自重置令牌,多个选项卡应该不会有太大问题。但要意识到这不是最佳的:
<a href="/User/logout?token=<?php echo getSessionToken(); ?>">Logout</a>
这绝对比没有好。但我仍然建议使用表格以获得最佳保护。
我强烈建议阅读并遵循OWASP CSRF预防 CSRF 指南。它会告诉你几乎所有你需要知道的,以及为什么......
在不更改 HTTP 方法的情况下,您可以向用户会话添加唯一 id 并将其附加到注销链接。如果执行注销操作并且两个 id 匹配,则注销有效。否则不是!
Rewrite to read like/Logout?#NONCE#, #NONCE# 是您从请求到请求更改的值。
您将不得不要求将某种验证器传递到注销页面。并且它必须是会话独有的并且难以猜测的东西。现在,如果只有一个合适的值.....哦,是的,会话标识符。
请注意,您应该使用 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();
}
我想我迟到了,但是,我是这样处理的:
<?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