CSRF token without cookies in PHP

无人久伴 提交于 2019-12-22 13:47:26

问题


I am looking for a way to add a CSRF token to an application I'm making. The caveat is, the application does not currently use cookies or sessions.

I would love to find a way to introduce a CSRF token without having to:

  1. Introduce state in my application.
  2. Use session or cookie ($_SESSION / $_COOKIE) storage

Is this at all a possibility, or am I stuck creating new state in my application.


回答1:


You can, but it's not going to be very secure.

Here's an example BUT DO NOT USE THIS, IT IS PROBABLY A BAD IDEA:

// 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
}

The downside is that these tokens are inherently reusable, so if one leaks an attacker can simply reuse (or recalculate) it. You can also try adding the form action="" value in the hash calculation.

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";
// ...

What's your anathema for sessions anyway?




回答2:


You can use a lightweight db and store a token, along with the ip adres, user agent, expiry time and requested url or you can try using a database and session storage to store a key with which tokens are created. 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 . "' />";



回答3:


CSRF protection works by comparing a token embedded in a page with a token associated with the browser that the page was sent to.

It is absolutely impossible to do this without introducing state.



来源:https://stackoverflow.com/questions/28679327/csrf-token-without-cookies-in-php

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!