CSRF token without cookies in PHP

匿名 (未验证) 提交于 2019-12-03 01:34:02

问题:

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.



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