PHP中没有cookie的CSRF令牌

时间:2015-02-23 17:10:13

标签: php security session cookies csrf

我正在寻找一种方法来将CSRF令牌添加到我正在制作的应用程序中。需要注意的是,应用程序当前不使用cookie或会话。

我很想找到一种方法来引入CSRF令牌,而不必:

  1. 在我的申请中介绍州。
  2. 使用会话或Cookie($_SESSION / $_COOKIE)存储
  3. 这是否可能,或者我在我的应用程序中无法创建新状态。

3 个答案:

答案 0 :(得分:1)

你可以,但它不会非常安全。

这是一个例子但不要使用它,这可能是一个糟糕的想法

// Do this somewhere
define('CSRF_SALT', '4dedMj4CWgBMNhRsoTpJlokwB5wTz7UsmF8Mq4uzFIbv');

$token = base64_encode(
    hash_hmac(
        'sha256', 
        date('Ymd') . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'],
        CSRF_SALT,
        true
    )
);

if (\hash_equals($_POST['security_token'], $token)) {
    // Form passes validation
}

缺点是这些令牌本质上是可重用的,因此如果一个泄漏,攻击者可以简单地重用(或重新计算)它。您还可以尝试在哈希计算中添加表单action =“”值。

function getToken($action)
{
    return base64_encode(
        hash_hmac(
            'sha256', 
            hash_hmac(
                'sha256',
                date('Ymd') . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'],
                hash('sha256', $action, true),
                true
            ),
            CSRF_SALT,
            true
        )
    );
}

echo "<form action='register.php' method='post'>\n";
echo "<input type='hidden' name='security_token' value='".getToken('register.php')."' />\n";
// ...

无论如何,你对会话的诅咒是什么?

答案 1 :(得分:0)

您可以使用轻量级数据库并存储令牌,以及ip地址,用户代理,到期时间和请求的URL,或者您可以尝试使用数据库和会话存储来存储创建令牌的密钥。 E.g。

$post = array();
If (isset($_POST) && !empty($_POST)) {
    If (isset($_POST['csrftoken']) && isset($_SESSION['csrfkey'])) {
        // check if csrftoken exists in db and fetch the row
        $hash = hash('sha256', $row['String'] . $_SESSION['csrfKey']);
        // delete the db record
        If ($hash === $_POST['csrfToken']) {
           $post = (array) $_POST;
           // check if expiry time has not passed
           // check requested url 
           // check user agent and ip adres
        }
    }
    $_REQUEST = null;
    $_POST = null;
}

If (!isset($_SESSION['csrfKey'])) {
    $_SESSION['csrfKey'] = uniqid('key_', true);
}
$string = uniqid('token_', true);
$token = hash('sha256', $string . $_SESSION['csrfKey']);
// save token and string along with expirytime in db
echo "<input type='hidden' name='csrftoken' value='" . $token . "' />";

答案 2 :(得分:-1)

CSRF保护的工作原理是将页面中嵌入的令牌与发送该页面的浏览器关联的令牌进行比较。

如果不引入国家,绝对不可能这样做。