Cookie 型 Token 介绍与CSRF

简介

Token 用于防止数据重复提交或 CSRF 攻击,可以使用 SESSION 存储 Token,也可以使用 Cookie 进行存储。

使用 SESSION 时的一般步骤:

  1. 后端生成随机字符串 Token,存储在服务器的 SESSION 中
  2. 当有表单时,从 SESSION 中取出 Token,写入一个隐藏框中,放到表单最底部
  3. 接受到 POST 数据后,判断 $_POST['token'] === $_SEESION['token']

由于某些原因,不能使用 SESSION,因此使用 COOKIE 进行存储 TOKEN,与 SESSION 类似,使用 COOKIE 时的一般步骤:

  1. 后端生成随机字符串,存储在 客户端的 COOKIE 中,返回给前端
  2. 当有表单时,从 Cookie 中取出 Token,写入一个隐藏框中,放到表单底部:<input type="hidden" name="token" value="<?php echo $token;?>"/>,同时访问时,HTTP头会自动带上 COOKIE
  3. 接收到 POST 数据后,判断 $_POST['token'] === $_COOKIE['token']

代码实现

使用 COOKIE 存储 Token 代码如下:

<?php
    $token = "";
    function setToken() {
        $GLOBALS['token'] = md5(microtime());
        setcookie("token", $GLOBALS['token']); 
    }

    function validToken() {
        $return = ($_POST['token'] === $_COOKIE['token'] ? true : false);
        setToken();
        return $return;
    }

    if(!isset($_POST['text'])) {
        setToken();
    } else {
        if(validToken()) {
            echo '验证通过';
            exit();
        } else {
            echo '非法操作';
            exit();
        }
    }
?>

<html>
<body>
    <form action="" method="post">
        <input type="hidden" name="token" value="<?php echo $token?>"/>
        <input type="text" name="text" value="val"/>
        <input type="submit" value="submit"/>
    </form>
</body>
</html>

跨域无法修改目标网站存在本地的 Cookie,所以在没有 XSS 漏洞时 Cookie 型 Token 是安全的,而破解的关键是:利用其它漏洞写入 Cookie,覆盖原有 Cookie,来达到 $_POST['token'] = $_COOKIE['token']

具体可参考: Cookie-Form型CSRF防御机制的不足与反思