Search code examples
phpsecuritysessioncookiescsrf

CSRF token without cookies in PHP


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.


Solution

  • 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?