веб-приложение facebook, ошибка при получении 'Состояние не соответствует. Вы можете стать жертвой CSRF - PullRequest
0 голосов
/ 06 ноября 2011

Я использую код с сайта разработчика приложений 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.");
   }

 ?>

Из кода видно, что по какой-то причине $ _REQUEST ['state']! = $ _SESSION ['state']. Может кто-нибудь объяснить, почему это происходит. Я также любитель PHP.

Спасибо тебе:)

Ответы [ 2 ]

0 голосов
/ 15 января 2012

Я понимаю, что этой проблеме уже 2 месяца, но у меня есть похожая проблема с использованием кода Heroku.Я еще не закончил отладку, но заметил, что вывод

session_id();

изменяется в IE после обновления, но остается неизменным в Chrome, предполагая, что сеанс теряется в IE.Очевидно, что в IE состояние сеанса будет пустым, и вы получите ошибку CSRF, в то время как в Chrome она работает нормально.

Если кто-то сможет пролить больше света на это, я был бы признателен.Я буду обновлять этот ответ, когда узнаю больше о том, что конкретно вызывает проблему в IE и как ее решить.

[править] Дух.Это проблема с cookie.Мой IE заблокировал файлы cookie (включая сеансовые файлы cookie), а Chrome - нет.Я получил идею после прочтения http://www.daniweb.com/web-development/php/threads/294235. Я не уверен, что обходной путь.Я буду держать это в курсе, как я узнаю больше.Любые комментарии от других приветствуются! [/ Edit]

[edit-2] Хорошо, как и обещали, вот решение.Вам нужно активировать P3P следующим образом:

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

Добавьте это в начало кода, где вы используете свои сеансы.Я нашел решение в Session Lost на IE Facebook App iFrame

Для полноты, вот код, который я использую (посмотрите метод входа в систему) -

<?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;
    //}
  }
}
0 голосов
/ 06 ноября 2011

Использовать SDK, намного проще.

Этот код получает пользовательские данные, сериализует их и отправляет в базу данных, я знаю, что это не идеально, но посмотрите.Я собираюсь отредактировать это, когда у меня будет немного свободного времени, затем я рекомендую кодировать данные пользователей в формате JSON, а не в виде сериализованной base64, поскольку в будущем будет проще выполнять поиск запросов.

<code>    <?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"
";эхо»"; echo"
"; 
      print_r($lk);
      echo"
"; endif?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...