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

发布于 2024-10-20 03:47:24 字数 221 浏览 6 评论 0原文

我的网站中有一个操作:

http://mysite.com/User/Logout

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

有什么想法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

原谅过去的我 2024-10-27 03:47:24

那么,您可以采取一些选项来帮助防范 CSRF 攻击:

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

    <提交名称=“注销”值=“注销”/> >

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

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

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

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

    function getSessionToken($reset = false) {
        if (!isset($_SESSION['random_token'])) {
            $_SESSION['random_token'] = sha1(uniqid(mt_rand(), true));
        }
        $token = $_SESSION['random_token'];
        如果($重置){
            取消设置($_SESSION['random_token']);
        }
        返回$令牌;
    }
    

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

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

    注销;
    

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

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

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

嗳卜坏 2024-10-27 03:47:24

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

请记住,虽然在这种情况下使用 GET 不符合 RFC,但这并不是您需要更改的所有内容来防止 XSRF。请参阅 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.

倥絔 2024-10-27 03:47:24

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

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!

青衫负雪 2024-10-27 03:47:24

重写为/Logout?#NONCE#,#NONCE# 是您在不同请求之间更改的值。

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

念﹏祤嫣 2024-10-27 03:47:24

您将必须要求将某种验证器传递到注销页面。而且它必须是会议独有的、难以猜测的安慰。现在,如果有一个合适的值就好了……哦,是的,会话标识符。

请注意,您应该使用 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();
   }

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();
   }
腹黑女流氓 2024-10-27 03:47:24

我想我参加聚会迟到了,但是,这是我的处理方式:

<?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-防护等级

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文