facebook web应用,获取错误“状态不匹配”。你可能是CSRF的受害者

facebook web应用,获取错误“状态不匹配”。你可能是CSRF的受害者,facebook,facebook-graph-api,Facebook,Facebook Graph Api,我正在使用facebook应用程序开发者网站上的代码。我试过了,但出现以下错误: "The state does not match. You may be a victim of CSRF" 使用的代码如下: <?php $app_id = "YOUR_APP_ID"; $app_secret = "YOUR_APP_SECRET"; $my_url = "YOUR_URL"; session_start(); $code = $_REQUEST

我正在使用facebook应用程序开发者网站上的代码。我试过了,但出现以下错误:

"The state does not match. You may be a victim of CSRF"
使用的代码如下:

  <?php 

   $app_id = "YOUR_APP_ID";
   $app_secret = "YOUR_APP_SECRET";
   $my_url = "YOUR_URL";

   session_start();
   $code = $_REQUEST["code"];

   if(empty($code)) {
     $_SESSION['state'] = md5(uniqid(rand(), TRUE)); //CSRF protection
     $dialog_url = "http://www.facebook.com/dialog/oauth?client_id=" 
       . $app_id . "&redirect_uri=" . urlencode($my_url) . "&state="
       . $_SESSION['state'];

     echo("<script> top.location.href='" . $dialog_url . "'</script>");
   }

   if($_REQUEST['state'] == $_SESSION['state']) {
     $token_url = "https://graph.facebook.com/oauth/access_token?"
       . "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url)
       . "&client_secret=" . $app_secret . "&code=" . $code;

     $response = file_get_contents($token_url);
     $params = null;
     parse_str($response, $params);

     $graph_url = "https://graph.facebook.com/me?access_token=" 
       . $params['access_token'];

     $user = json_decode(file_get_contents($graph_url));
     echo("Hello " . $user->name);
   }
   else {
     echo("The state does not match. You may be a victim of CSRF.");
   }

 ?>
从代码中可以看出,出于某种原因,$\u请求['state']!=$_会话['state']。谁能解释一下为什么会这样。我也是一名PHP业余爱好者

谢谢你:

使用SDK,简单多了

这段代码获取用户数据并将其序列化,然后抛出到数据库,我知道它并不完美,但请看一看。当我有空闲时间时,我会编辑这个,然后我建议将用户数据编码为JSON,而不是base64序列化,因为这样将来查询搜索会更容易

    <?php
        require 'facebook.php'; // USE FACEBOOK PHP SDK

        // Create our Application instance (replace this with your appId and secret).
        $facebook = new Facebook(array(
          'appId'  => 'APPID',
          'secret' => 'APPSECRET',
        ));
        // ----------------------------------------------------------------------------------------
        // ----------------------------------------------------------------------------------------

        // Get User ID
        $user = $facebook->getUser();

        /* We may or may not have this data based on whether the user is logged in.
           If we have a $user id here, it means we know the user is logged into
           Facebook, but we don't know if the access token is valid. An access
           token is invalid if the user logged out of Facebook. */

        if ($user) {
          try {
            // Proceed knowing you have a logged in user who's authenticated.
            // these are the graph calls
            $dt = $facebook->api('/me');
            $lk = $facebook->api('/me/likes');
          } catch (FacebookApiException $e) {
            error_log($e);
            $user = null;
          }
        }

        // ----------------------------------------------------------------------------------------
        // ----------------------------------------------------------------------------------------
        // Handler for Login Status
        // With the LoginURL, user the 'scope' to ask for permissions
        if ($user) {
          $logoutUrl = $facebook->getLogoutUrl();
        } else {
          $loginUrl = $facebook->getLoginUrl(array("scope" => "email,user_birthday,user_likes,user_work_history,user_location,user_education_history"));
        }
        // ----------------------------------------------------------------------------------------
        ?>
        <?php if (!$user): header ('Location:'.$loginUrl.''); //CHECKS IF USER IS LOGGED IN
        else: 

 // Do Something here. This next bit of code shows what comes out of those calls.
      echo "<pre>"; 
      print_r($dt);
      echo"</pre>";

      echo"<br/><br/>";

      echo "<pre>"; 
      print_r($lk);
      echo"</pre>";

      endif
        ?>

我确实意识到这个问题已经存在2个月了,但是我在使用Heroku代码时遇到了类似的问题。我还没有完全完成调试,但是我注意到

<?php

/**
 * This class provides Facebook specfic utility functions that you may use
 * to build your app.
 */


require_once('AppInfo.php');
require_once('utils.php');

class FBUtils {

  /*****************************************************************************
   *
   * The content below provides some helper functions that you may wish to use as
   * you develop your app.
   *
   ****************************************************************************/

  /**
   * GETs graph.facebook.com/$target, and returns it as decoded JSON
   * To learn more about the Graph API, visit:
   *  'https://developers.facebook.com/docs/refererence/api'
   *
   * @return graph api content of $target
   */
  public static function fetchFromFBGraph($target) {
   return self::curl('https://graph.facebook.com/' . $target);
  }

  /**
   * Uses FQL (Facebook Query Language) to return the result of $query with the
   * access-token $token.  FQL is used to process more complex requests that the
   * graph API does not directly expose.  For more information, visit
      'https://developers.facebook.com/docs/reference/fql'
   *
   * @return Facebook Query result for $query
   */
  public static function fql($query, $token) {
    $query = urlencode($query);
    return self::curl("https://api.facebook.com/method/fql.query?query=$query&format=json&access_token=$token");
  }

  /**
   * Helper function
   * @return the JSON decoded results of curling $url
   */
  public static function curl($url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    return json_decode(curl_exec($ch), true);
  }

  /**
   * Authenticates the current viewer of the app, prompting them to login and
   * grant permissions if necessary.  For more information, check the
   * 'https://developers.facebook.com/docs/authentication/'
   *
   * @return app access token if login is successful
   */
  public static function login($redirect) {
    $app_id = AppInfo::appID();
    //echo "app id: $app_id <br>";
    $app_secret = AppInfo::appSecret();
    //echo "app secret: $app_secret <br>";
    $home = AppInfo::getHome();
    //echo "home: $home <br>";
    // Scope defines what permissions that we are asking the user to grant.
    // In this example, we are asking for the ability to publish stories
    // about using the app, access to what the user likes, and to be able
    // to use their pictures.  You should rewrite this scope with whatever
    // permissions your app needs.
    // See https://developers.facebook.com/docs/reference/api/permissions/
    // for a full list of permissions
    $scope = 'user_likes,user_photos,user_photo_video_tags,publish_stream';
    //session_start();
    $code = $_REQUEST["code"];
    // If we don't have a code returned from Facebook, the first step is to get
    // that code
    if (empty($code)) {
        //echo "test"; exit();
      // CSRF protection - for more information, look at 'Security Considerations'
      // at 'https://developers.facebook.com/docs/authentication/'
      $state = md5(uniqid(rand(), TRUE));
      setcookie(
        AppInfo::appID() . '-fb-app',
        $state,
        $expires = time()+3600,
        $path = "",
        $domain = "",
        $secure = "",
        $httponly = true); 
        $_SESSION[AppInfo::appID() . '-fb-app'] = $state;
        echo session_id(); exit(); // debugging output
      // Now form the login URL that you will use to authorize your app
      $authorize_url = "https://www.facebook.com/dialog/oauth?client_id=$app_id" .
"&redirect_uri=$home&state=" . $state . "&scope=$scope";
      // Now we redirect the user to the login page
      echo("<script> window.location.href='" . $authorize_url . "'</script>");
      return false;
    // Once we have that code, we can now request an access-token.  We check to
    // ensure that the state has remained the same.
    } else 
    {
        echo $_REQUEST['state']."|"; echo $_SESSION[AppInfo::appID() . '-fb-app']; exit(); // debugging output
    if ($_REQUEST['state'] === $_COOKIE[AppInfo::appID() . '-fb-app']) {
      $ch = curl_init("https://graph.facebook.com/oauth/access_token");
      curl_setopt($ch, CURLOPT_POSTFIELDS,
        "client_id=$app_id&redirect_uri=$home&client_secret=$app_secret" .
        "&code=$code&scope=$scope");
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      $response = curl_exec($ch);
      // Once we get a response, we then parse it to extract the access token
      parse_str($response, $params);
      $token = $params['access_token'];
      return $token;
    // In the event that the two states do not match, we return false to signify
    // that something has gone wrong during authentication
    }}
    //else {
    //  echo("States do not match.  CSRF?");
    //  return false;
    //}
  }
}
刷新后IE中的更改,但在Chrome中保持不变,表明会话在IE中丢失。显然,会话状态在IE中为空,在Chrome下正常工作时,您将收到CSRF错误

如果有人能更清楚地说明这一点,我将不胜感激。我会不断更新这个答案,因为我会进一步了解到底是什么导致了IE中的问题以及如何解决它

[编辑]嗯。这是一个饼干问题。我的IE阻止了coockies,包括会话cookies,而Chrome没有。我读了之后有了这个想法。不过,我不确定解决办法。当我发现更多信息时,我会不断更新。欢迎他人提供任何意见![/编辑]

[edit-2]好的,正如承诺的那样,这是解决方案。您需要像这样激活P3P:

将此添加到您正在使用会话的代码顶部。我找到了解决办法

为了完整起见,下面是我正在使用的代码看看登录方法-

header('P3P: CP="CAO PSA OUR"');
<?php

/**
 * This class provides Facebook specfic utility functions that you may use
 * to build your app.
 */


require_once('AppInfo.php');
require_once('utils.php');

class FBUtils {

  /*****************************************************************************
   *
   * The content below provides some helper functions that you may wish to use as
   * you develop your app.
   *
   ****************************************************************************/

  /**
   * GETs graph.facebook.com/$target, and returns it as decoded JSON
   * To learn more about the Graph API, visit:
   *  'https://developers.facebook.com/docs/refererence/api'
   *
   * @return graph api content of $target
   */
  public static function fetchFromFBGraph($target) {
   return self::curl('https://graph.facebook.com/' . $target);
  }

  /**
   * Uses FQL (Facebook Query Language) to return the result of $query with the
   * access-token $token.  FQL is used to process more complex requests that the
   * graph API does not directly expose.  For more information, visit
      'https://developers.facebook.com/docs/reference/fql'
   *
   * @return Facebook Query result for $query
   */
  public static function fql($query, $token) {
    $query = urlencode($query);
    return self::curl("https://api.facebook.com/method/fql.query?query=$query&format=json&access_token=$token");
  }

  /**
   * Helper function
   * @return the JSON decoded results of curling $url
   */
  public static function curl($url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    return json_decode(curl_exec($ch), true);
  }

  /**
   * Authenticates the current viewer of the app, prompting them to login and
   * grant permissions if necessary.  For more information, check the
   * 'https://developers.facebook.com/docs/authentication/'
   *
   * @return app access token if login is successful
   */
  public static function login($redirect) {
    $app_id = AppInfo::appID();
    //echo "app id: $app_id <br>";
    $app_secret = AppInfo::appSecret();
    //echo "app secret: $app_secret <br>";
    $home = AppInfo::getHome();
    //echo "home: $home <br>";
    // Scope defines what permissions that we are asking the user to grant.
    // In this example, we are asking for the ability to publish stories
    // about using the app, access to what the user likes, and to be able
    // to use their pictures.  You should rewrite this scope with whatever
    // permissions your app needs.
    // See https://developers.facebook.com/docs/reference/api/permissions/
    // for a full list of permissions
    $scope = 'user_likes,user_photos,user_photo_video_tags,publish_stream';
    //session_start();
    $code = $_REQUEST["code"];
    // If we don't have a code returned from Facebook, the first step is to get
    // that code
    if (empty($code)) {
        //echo "test"; exit();
      // CSRF protection - for more information, look at 'Security Considerations'
      // at 'https://developers.facebook.com/docs/authentication/'
      $state = md5(uniqid(rand(), TRUE));
      setcookie(
        AppInfo::appID() . '-fb-app',
        $state,
        $expires = time()+3600,
        $path = "",
        $domain = "",
        $secure = "",
        $httponly = true); 
        $_SESSION[AppInfo::appID() . '-fb-app'] = $state;
        echo session_id(); exit(); // debugging output
      // Now form the login URL that you will use to authorize your app
      $authorize_url = "https://www.facebook.com/dialog/oauth?client_id=$app_id" .
"&redirect_uri=$home&state=" . $state . "&scope=$scope";
      // Now we redirect the user to the login page
      echo("<script> window.location.href='" . $authorize_url . "'</script>");
      return false;
    // Once we have that code, we can now request an access-token.  We check to
    // ensure that the state has remained the same.
    } else 
    {
        echo $_REQUEST['state']."|"; echo $_SESSION[AppInfo::appID() . '-fb-app']; exit(); // debugging output
    if ($_REQUEST['state'] === $_COOKIE[AppInfo::appID() . '-fb-app']) {
      $ch = curl_init("https://graph.facebook.com/oauth/access_token");
      curl_setopt($ch, CURLOPT_POSTFIELDS,
        "client_id=$app_id&redirect_uri=$home&client_secret=$app_secret" .
        "&code=$code&scope=$scope");
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      $response = curl_exec($ch);
      // Once we get a response, we then parse it to extract the access token
      parse_str($response, $params);
      $token = $params['access_token'];
      return $token;
    // In the event that the two states do not match, we return false to signify
    // that something has gone wrong during authentication
    }}
    //else {
    //  echo("States do not match.  CSRF?");
    //  return false;
    //}
  }
}