【问题标题】:Setting PHP session on index page for XSRF check在索引页面上设置 PHP 会话以进行 XSRF 检查
【发布时间】:2013-12-10 09:29:27
【问题描述】:

我遇到了以下关于 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;
   }
}

【问题讨论】:

  • 您是在 $http 调用中发布到 index.php 还是服务器上的其他 php 页面?如果我理解您的问题,是 php 文件获得了一个空会话?
  • 如果我理解正确...如果您希望它可用于 ajax 请求,您可以使用 PHP 生成 XSRF 令牌变量并放入 JS 代码...也许您的一些示例代码会有所帮助?
  • 没有理由不这样做。在第一个请求中,您创建一个会话和一个令牌,并在您的第一个响应中返回会话 cookie。会话现在存在,所有后续请求都有一个活动会话。我们需要更多详细信息来帮助您。
  • 大家好,感谢您的回复。稍后我会尝试发布一些代码,但基本上我不会发布到同一个 index.php 文件。所有 Ajax 请求都发布到同一个通用 php 页面。我正在检查会话,它只是不存在....直到页面重新加载。
  • 大家好,很抱歉耽误了您的时间。它现在对我有用,但有趣的是我并没有太大变化。我更改了会话变量的名称,突然一切正常.. 很奇怪..

标签: php angularjs session csrf


【解决方案1】:

这就是我在我的 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 保护。

【讨论】:

  • 您好,谢谢您的回答。这也是我的基本做法。顺便说一句,检查 http 标头出现的更简单方法是使用 $headerToken = $_SERVER['HTTP_XSRF_TOKEN'],无需遍历所有标头。还要记住,Angular 只在 POST、PUT 和 DELETE 请求上发送标头,而不是在 GET 上
  • 我建议放一些比 microtime() 更独特的东西作为“随机”生成器,例如,放置用户的 ID、IP 地址、访问的页面等,会增加复杂性并使其更难猜测 XSRF-TOKEN。我还建议通过使用 httponly(如果可能)和路径参数来最小化 cookie 的暴露
  • 另外,您不必为 Angular 创建一个 cookie 来读取。只需设置一个 CONSTANT(请参阅我的更新)
  • 这和使用 cookie 一样安全吗?
  • 不明白为什么不呢?它被注入到 AngularJS 中——并且只在 index.php 页面上提供...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-27
  • 1970-01-01
  • 2020-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多