在索引页面上设置PHP会话以进行XSRF检查

时间:2013-11-25 15:23:41

标签: php angularjs session csrf

我遇到了有关XSRF令牌的以下问题。

客户:AngularJS 服务器:PHP

当命中index.php时,PHP会生成一个XSRF令牌并将其保存在会话中。 Cookie设置为相同的值。

AngularJS读取cookie并存储值。

在后续的POSTS上,XSRF令牌作为标头发送,其目的是将存储的会话令牌与发送的头部进行比较。

一切似乎都很好,没有任何问题。

但是:问题是,PHP无法读取index.php中注册的会话,因为从技术上讲,没有页面重新加载!如果我点击F5并重新加载所有内容,那么会话就会很好地阅读。

如何在index.php上设置XSRF会话令牌并使其可用于后续来自客户端的ajax请求?我正在拔掉我的头发...欣赏反馈。

更新

更改会话标识符名称后,一切都突然发挥作用!

在index.php中:

// Create token and set session
session_start();
$token = hash('sha256', uniqid(mt_rand(), true));
$_SESSION['XSRF']=$token; 

稍后,也在index.php中:

/* Give token to Angular client */
<script>
angular.module("app").constant("CSRF_TOKEN", '<?=$_SESSION['XSRF'];?>'); 
</script>

请注意,我没有使用cookie,而是设置了一个常量,然后可以将其用于Angular中的.run方法:

Angular中的

angular.module('app').run(['CSRF_TOKEN','$http',function(CSRF_TOKEN,$http) {

   $http.defaults.headers.common['CSRF_TOKEN'] = CSRF_TOKEN;

对服务器的所有请求都被路由到一个常见的php文件。该文件检查标头是否已设置,并比较两个标记:

// Only POST requests are checked (I don't use PUT/DELETE)
if($_SERVER['REQUEST_METHOD']=="POST"){
   session_start();
   $headerToken = $_SERVER['HTTP_CSRF_TOKEN'];
   $sessionToken = $_SESSION['XSRF'];
   if($headerToken!=$sessionToken){
      header('HTTP/1.0 401 Unauthorized');
      exit;
   }
}

1 个答案:

答案 0 :(得分:4)

这就是我在PHP / AngularJS项目中所做的事情:

的index.php

session_start();
if (!isset($_SESSION['XSRF-TOKEN'])) {
    $uniqueValues = md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']); //add more/less/any "unique" values, see comments
    $_SESSION['XSRF-TOKEN'] = sha1(uniqid(microtime() . $uniqueValues, true));
    setcookie('XSRF-TOKEN', $_SESSION['XSRF-TOKEN']);
}

AngularJS调用的任何脚本$ http:

(AngluarJS使用cookie XSRF-TOKEN的值,并将其作为X-XSRF-TOKEN自定义标头在每个请求中发送,因此我们需要将此值与会话中存储的值进行比较。)

function verifyXSRF() {

    /*
    $headers = apache_request_headers();
    $headerToken = "";
    foreach ($headers as $header => $value) {
        if ($header == "X-XSRF-TOKEN") {
            $headerToken = $value;
            break;          
        }
    }
    */

    //more efficient, see comments
    $headerToken = $_SERVER['HTTP_X_XSRF_TOKEN'];

    if ($headerToken != $_SESSION['XSRF-TOKEN']) return false;
    return true;
}

session_start();
if (!verifyXSRF()) die("XSRF error");

欢迎反馈,因为我不确切知道这是否足以保护XSRF。