web-dev-qa-db-fra.com

Le SDK Facebook a renvoyé une erreur: la validation de la falsification de requête intersite a échoué. Le paramètre "state" de l'URL et de la session ne correspond pas

j'essaie d'obtenir l'identifiant de l'utilisateur Facebook en utilisant le SDK php comme celui-ci 

$fb = new Facebook\Facebook([
    'app_id' => '11111111111',
    'app_secret' => '1111222211111112222',
    'default_graph_version' => 'v2.4',
]);

$helper = $fb->getRedirectLoginHelper();


$permissions = ['public_profile','email']; // Optional permissions
$loginUrl = $helper->getLoginUrl('http://MyWebSite', $permissions);

echo '<a href="' . $loginUrl . '">Log in with Facebook!</a>';


    try {
        $accessToken = $helper->getAccessToken();
        var_dump($accessToken);
    } catch (Facebook\Exceptions\FacebookResponseException $e) {
        // When Graph returns an error
        echo 'Graph returned an error: ' . $e->getMessage();
        exit;
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // When validation fails or other local issues
        echo 'Facebook SDK returned an error: ' . $e->getMessage();
        exit;
    }

    if (!isset($accessToken)) {
        if ($helper->getError()) {
            header('HTTP/1.0 401 Unauthorized');
            echo "Error: " . $helper->getError() . "\n";
            echo "Error Code: " . $helper->getErrorCode() . "\n";
            echo "Error Reason: " . $helper->getErrorReason() . "\n";
            echo "Error Description: " . $helper->getErrorDescription() . "\n";
        } else {
            header('HTTP/1.0 400 Bad Request');
            echo 'Bad request';
        }
        exit;
    }

// Logged in
    echo '<h3>Access Token</h3>';
    var_dump($accessToken->getValue());

// The OAuth 2.0 client handler helps us manage access tokens
    $oAuth2Client = $fb->getOAuth2Client();

// Get the access token metadata from /debug_token
    $tokenMetadata = $oAuth2Client->debugToken($accessToken);
    echo '<h3>Metadata</h3>';
    var_dump($tokenMetadata);

// Validation (these will throw FacebookSDKException's when they fail)
    $tokenMetadata->validateAppId($config['11111111111']);
// If you know the user ID this access token belongs to, you can validate it here
//$tokenMetadata->validateUserId('123');
    $tokenMetadata->validateExpiration();

    if (!$accessToken->isLongLived()) {
        // Exchanges a short-lived access token for a long-lived one
        try {
            $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
        } catch (Facebook\Exceptions\FacebookSDKException $e) {
            echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n";
            exit;
        }

        echo '<h3>Long-lived</h3>';
        var_dump($accessToken->getValue());
    }

    $_SESSION['fb_access_token'] = (string)$accessToken;

mais cela me donne cette erreur:

Facebook SDK returned an error: 
Cross-site request forgery validation failed. 
The "state" param from the URL and session do not match.

s'il vous plaît toute aide je suis nouveau dans php et Facebook SDK remercier pour toute aide à l'avance.

51
Fadi

J'ai constaté que tant que j'autorisais les sessions PHP avant de générer l'URL de connexion, et en haut du script que redirige éventuellement vers Facebook, cela fonctionnait tout seul sans installer de cookie ( selon la réponse de a500 ). Ceci utilise la version 5.1 du SDK.

Au sommet des deux scripts, j'ai ajouté ...

if(!session_id()) {
    session_start();
}

... et cela "a juste fonctionné".

Voici un exemple complet barebones qui a fonctionné pour moi:

auth.php

if (!session_id()) {
    session_start();
}

$oFB = new Facebook\Facebook([
    'app_id'     => FACEBOOK_APP_ID,
    'app_secret' => FACEBOOK_APP_SECRET
]);

$oHelper = self::$oFB->getRedirectLoginHelper();
$sURL = $oHelper->getLoginUrl(FACEBOOK_AUTH_CALLBACK, FACEBOOK_PERMISSIONS);

// Redirect or show link to user.

auth_callback.php

if (!session_id()) {
    session_start();
}

$oFB = new Facebook\Facebook([
    'app_id'     => FACEBOOK_APP_ID,
    'app_secret' => FACEBOOK_APP_SECRET
]);

$oHelper = self::$oFB->getRedirectLoginHelper();
$oAccessToken = $oHelper->getAccessToken();
if ($oAccessToken !== null) {
    $oResponse = self::$oFB->get('/me?fields=id,name,email', $oAccessToken);
    print_r($oResponse->getGraphUser());
}

Pourquoi?

De plus, cela est expliqué dans la documentation sur le référentiel. Regardez l'avertissement sur cette page .

Avertissement: FacebookRedirectLoginHelper utilise des sessions pour stocker une valeur CSRF. Vous devez vous assurer que les sessions sont activées avant d'appeler la méthode getLoginUrl (). Cela se fait généralement automatiquement dans la plupart des frameworks web, mais si vous n'utilisez pas de framework web, vous pouvez ajouter session_start (); en haut de vos scripts login.php & login-callback.php. Vous pouvez écraser la gestion de session par défaut - voir les points d'extensibilité ci-dessous.

J'ajoute cette note car il est important de garder à l'esprit si vous exécutez votre propre gestion de session ou si vous utilisez plusieurs serveurs Web en parallèle. Dans ces cas, compter sur les méthodes de session par défaut de php ne fonctionnera pas toujours.

93
enobrev

insérez ce code après $ helper = $ fb-> getRedirectLoginHelper ();

  $_SESSION['FBRLH_state']=$_GET['state'];

et cela fonctionnera ou pour plus de détails visitez les applications de connexion facebook

63
zratan

Beaucoup de bonnes réponses déjà mentionnées, voici celle qui m'a aidé, 

J'ai constaté que le problème est La validation de la falsification d'une requête intersite a échoué Param requis “état” manquant dans le code FB et voici la solution

Après cette ligne

$helper = $fb->getRedirectLoginHelper();

Ajoutez le code ci-dessous,

if (isset($_GET['state'])) {
    $helper->getPersistentDataHandler()->set('state', $_GET['state']);
}
47
G.Ashok Kumar

J'ai eu cette erreur en utilisant le SDK de Facebook dans Symfony2, en écrivant une extension Twig pour afficher les données de l'API dans des modèles.

La solution pour moi consistait à ajouter 'persistent_data_handler'=>'session' à la configuration d'objet Facebook, ce qui a pour effet de stocker les données d'état dans une clé de session au lieu de la mémoire:

$fb = new Facebook\Facebook([
    'app_id' => 'APP_ID',
    'app_secret' => 'APP_SECRET',
    'default_graph_version' => 'v2.4',
    'persistent_data_handler'=>'session'
]);

Par défaut, il utilisait le gestionnaire de mémoire intégré, qui ne fonctionnait pas correctement pour moi. Peut-être parce que certaines fonctions sont appelées depuis une extension Twig, car le gestionnaire de mémoire fonctionne lorsque le SDK est utilisé exclusivement dans des contrôleurs/services normaux.

Apparemment, l'état est défini lorsque vous appelez getLoginUrl() et est récupéré chaque fois que vous appelez getAccessToken(). Si l'état enregistré renvoie null (car votre gestionnaire de données n'est pas en tant que persistent comme il se doit), la vérification de validation CSRF échoue. 

Si vous avez besoin de traiter les sessions d'une manière particulière ou si vous souhaitez stocker l'état ailleurs, vous pouvez également écrire votre propre gestionnaire avec 'persistent_data_handler' => new MyPersistentDataHandler(), en utilisant par exemple FacebookSessionPersistentDataHandler.

20
Fx32

Cela se produit lorsque la bibliothèque Facebook ne peut pas faire correspondre le paramètre d'état reçu de Facebook avec celui qu'elle a défini par défaut dans la session. Si vous utilisez un framework tel que Laravel, Yii2 ou Kohana qui implémente son propre stockage de session, l'implémentation de session Facebook standard ne fonctionnera probablement pas.

Pour résoudre ce problème, vous devez créer votre propre implémentation de PersistentDataInterface à l'aide de la bibliothèque de session de votre infrastructure et le transmettre au constructeur Facebook\Facebook.

Voici un exemple de gestionnaire de persistance Laravel de Facebook :

use Facebook\PersistentData\PersistentDataInterface;

class MyLaravelPersistentDataHandler implements PersistentDataInterface
{
  /**
   * @var string Prefix to use for session variables.
   */
  protected $sessionPrefix = 'FBRLH_';

  /**
   * @inheritdoc
   */
  public function get($key)
  {
    return \Session::get($this->sessionPrefix . $key);
  }

  /**
   * @inheritdoc
   */
  public function set($key, $value)
  {
    \Session::put($this->sessionPrefix . $key, $value);
  }
}

Exemple de paramètre constructeur:

$fb = new Facebook\Facebook([
  // . . .
  'persistent_data_handler' => new MyLaravelPersistentDataHandler(),
  // . . .
 ]);

Plus d'infos ici: https://developers.facebook.com/docs/php/PersistentDataInterface/5.0.0

14
George

Enfin, en regardant dans le code FB, j’ai découvert que le problème 

Échec de la validation de la requête intersite. Param requis “état” manquant

et des similitudes sont causées par la variable PHP $_SESSION['FBRLH_state'] qui, pour une raison "étrange", lorsque FB appelle le fichier login-callback.

Pour le résoudre, je stocke cette variable "FBRLH_state" APRES l'appel de la fonction $helper->getLoginUrl(...). Il est très important de ne le faire qu'après l'appel de cette fonction car c'est à l'intérieur de cette fonction que la variable $_SESSION['FBRLH_state'] est renseignée.

Ci-dessous un exemple de mon code dans le login.php:

$uri=$helper->getLoginUrl($uri, $permissions);
foreach ($_SESSION as $k=>$v) {                    
    if(strpos($k, "FBRLH_")!==FALSE) {
        if(!setcookie($k, $v)) {
            //what??
        } else {
            $_COOKIE[$k]=$v;
        }
    }
}
var_dump($_COOKIE);

Et dans le fichier login-callback.php avant d'appeler tout le code FB:

foreach ($_COOKIE as $k=>$v) {
    if(strpos($k, "FBRLH_")!==FALSE) {
        $_SESSION[$k]=$v;
    }
}

Dernier point, mais non le moindre, n'oubliez pas d'inclure également du code pour la session PHP, donc ..

if(!session_id()) {
    session_start();
}
...
...
...
...
<?php session_write_close() ?>

J'espère que cette réponse pourra vous aider à économiser 8 à 10 heures de travail:) Bye, Alex.

8
ale500

Pour moi, le problème était que je n'exécutais pas de session avant le script.

J'ai donc ajouté session_start(); avant d'instancier la classe Facebook.

7
Nino Škopac

Le même problème m’a frappé sur laravel 5.4 j’ai résolu ce problème en mettant 

session_start();

en haut du script.

Vous trouverez ci-dessous un exemple d'espace de noms de contrôleur laravel pour vous donner un exemple d'utilisation.

<?php
namespace App\Http\Controllers;
session_start();
use Facebook\Facebook as Facebook;
?>

le problème se produit car il n'a pas encore démarré. En ajoutant le début de la session en haut du script, nous commençons à peine la session.

j'espère que ça peut aider quelqu'un .. 

4
usama

L'objet Facebook a une variable d'instance appelée persistentDataHandler, généralement une instance de FacebookSessionPersistentDataHandler, qui contient un ensemble et une méthode get pour accéder aux sessions natives PHP.

Lors de la génération de l'URL de rappel en utilisant: 

$loginUrl = $helper->getLoginUrl($callback_url, $permissions);

La méthode FacebookRedirectLoginHelper->getLoginUrl() va créer une chaîne aléatoire de 32 caractères, l'ajouter au $loginUrl et l'enregistrer dans le code ci-dessous à l'aide de la méthode set de la persistentDataHandler.

$_SESSION['FBRLH_' . 'state']

Plus tard, lorsque la $helper->getAccessToken(); sera appelée, l'état param dans l'URL sera comparé à celui stocké dans la même session pour empêcher CSRF. S'il ne correspond pas, cette exception sera levée.

FacebookSDKException: La validation de la falsification de requête intersite a échoué. Param requis "état" manquant.

Tout cela étant dit, vous devez vous assurer que votre fonction de session native PHP est correctement définie au cours de ce processus. Vous pouvez le vérifier en ajoutant 

die($_SESSION['FBRLH_' . 'state']);

après

$loginUrl = $helper->getLoginUrl($callback_url, $permissions);

et avant 

$accessToken = $helper->getAccessToken();

pour voir si cette chaîne de 32 caractères est là. 

J'espère que ça aide!

3
Chao Chen

Avec Symfony, cela ne fonctionne pas car la façon dont les sessions sont gérées. 

Pour résoudre le problème, vous pouvez créer un nouveau gestionnaire qui fonctionne avec la session de symfony.

FacebookDataHandlerSymfony.php: 

<?php

use Facebook\PersistentData\PersistentDataInterface;
use Symfony\Component\HttpFoundation\Session\Session;

class FacebookDataHandlerSymfony implements PersistentDataInterface
{

    private $session;

    public function __construct()
    {
        $this->session = new Session();
    }

    public function get($key)
    {
        return $this->session->get('FBRLH_' . $key);
    }

    public function set($key, $value)
    {
        $this->session->set('FBRLH_' . $key, $value);
    }

}

Et lorsque vous créez l'objet FB, il vous suffit de spécifier la nouvelle classe: 

$this->fb = new Facebook([
            'app_id' => '1234',
            'app_secret' => '1324',
            'default_graph_version' => 'v2.8',
            'persistent_data_handler' => new FacebookDataHandlerSymfony()
        ]);
2
user4520510

Cela pourrait être un peu tard, mais j'espère que cela aidera les autres, car ce problème persiste encore.

J'ai eu ce problème pendant un certain temps et j'ai cherché autour de moi et j'ai vu beaucoup de solutions différentes, dont beaucoup désactivent le contrôle CSRF. Donc, après tout ce que j'ai lu, voici ce qui a fonctionné pour moi.

Si j'ai bien compris, vous obtenez cette erreur lorsque votre URL de redirection ne correspond pas à celle que vous avez configurée dans les paramètres de votre application. Mon problème a donc été résolu facilement, mais j'ai également vu des personnes rencontrer des problèmes en ne démarrant pas correctement leur session. Je vais couvrir les deux questions.

Étape 1: Assurez-vous que votre session a démarré au moment opportun.

par exemple: fb-config.php

session_start();
include_once 'path/to/Facebook/autoload.php';

$fb = new \Facebook\Facebook([
    'app_id' => 'your_app_id',
    'app_secret' => 'your_secret_app_id',
    'default_graph_version' => 'v2.10'
]);

$helper = $fb->getRedirectLoginHelper();

si votre code de rappel facebook est sur un autre fichier en dehors de la configuration, démarrez la session sur ce fichier également.

par exemple: fb-callback.php

session_start();
include_once 'path/to/fb-config.php';

try {
    $accessToken = $helper->getAccessToken();
} catch (\Facebook\Exceptions\FacebookResponseException $e) {
    echo "Response Exception: " . $e->getMessage();
    exit();
} catch (\Facebook\Exceptions\FacebookSDKException $e) {
    echo "SDK Exception: " . $e->getMessage();
    exit();
}

/** THE REST OF YOUR CALLBACK CODE **/

Maintenant, qu'est-ce qui a résolu mon problème actuel?.

Étape 3: Configurez votre URL de redirection dans les paramètres de votre application.

Dans les paramètres de votre application de connexion Facebook, accédez à l'URI de redirection Valid OAuth où vous auriez dû ajouter l'URL qui pointe vers votre fichier fb-callback.php.

http://example.com/fb-callback.php

AND ALSO

http://www.example.com/fb-callback.php

puis configurez votre URL de redirection comme suit.

$redirectURL = "http://".$_SERVER['SERVER_NAME']."/fb-callback.php";
$permissions = ['email'];
$fLoginURL = $helper->getLoginUrl($redirectURL, $permissions);

Pourquoi à la fois avec et sans www et pourquoi utiliser SERVER_NAME?

parce que votre URI de redirection Valid OAuth doit correspondre à votre URL de redirection dans votre code et si dans les paramètres de votre application, vous définissez uniquement votre redirection OAuth sur http://example.com/fb-callback.php et configurez votre $ redirectURL en tant que http://example.com/fb-bacllback.php pour le faire correspondre, mais l'utilisateur a entré votre site sous la forme http://www.example.com puis l'utilisateur obtiendra l'erreur Facebook SDK: la validation de la falsification de requête intersite a échoué. Param requis "état" manquant dans les données persistantes car l'URL de l'utilisateur ne correspond pas EXACTEMENT à ce que vous avez configuré. Pourquoi? Je n'ai aucune idée terrifiante.

Si mon utilisateur accède à votre site par le biais de http://example.com ou http://www.example.com , mon approche le fera toujours correspondre à ce que vous avez configuré dans les paramètres de votre application. Pourquoi? car $ _SERVER ['SERVER_NAME'] renverra le domaine avec ou sans le www en fonction de la manière dont l'utilisateur a saisi l'URL dans le navigateur.

Ce sont mes conclusions et c'est à peu près la seule chose qui a fonctionné pour moi sans supprimer le contrôle CSRF et jusqu'à présent, aucun problème.

J'espère que ça aide.

2
BlueSun3k1

vous pouvez simplement faire cela définir la session avec le nouvel état

<?php
if(isset($_GET['state'])) {
      if($_SESSION['FBRLH_' . 'state']) {
          $_SESSION['FBRLH_' . 'state'] = $_GET['state'];
      }
}
?>

vous recevez cette erreur si votre nom d’hôte Origin est différent du nom d’hôte cible une fois authentifié.

$loginUrl = $helper->getLoginUrl('http://MyWebSite', $permissions);

avec cette déclaration, si le visiteur de votre site Web a utilisé http://www.mywebsite.com/ , l'erreur intersite sera générée.

Vous devez vous assurer que l'origine et le nom d'hôte cible sont exactement les mêmes, y compris le préfixe www éventuel.

Version fixe:

$loginUrl = $helper->getLoginUrl('http://'.$_SERVER['SERVER_NAME'], $permissions);
2
Jean.R

Solution facile pour moi ... j'ai changé:

$loginUrl = $helper->getLoginUrl('http://www.MYWEBSITE.ca/index_callback.php', $permissions);

à:

$loginUrl = $helper->getLoginUrl('http://MYWEBSITE.ca/index_callback.php', $permissions);

supprimer le 'www' a résolu le problème.

1
Mathieu Wilson

Dans mon cas, j'ai vérifié l'erreur et trouvé l'erreur qui m'a amené à la solution avec le code d'exécution:

date_default_timezone_set('Europe/Istanbul');

avant le script. Travaillé comme un charme. Pour votre emplacement, vérifiez: timezones.europe.php

1
Roman Losev

Yii2 solution qui fonctionne pour moi:

use Facebook\PersistentData\PersistentDataInterface;
use Yii;

class PersistentDataHandler implements PersistentDataInterface
{
    /**
     * @var string Prefix to use for session variables.
     */
    protected $sessionPrefix = 'FBRLH_';

    public function get($key)
    {
        return Yii::$app->session->get($this->sessionPrefix . $key);
    }

    public function set($key, $value)
    {
        Yii::$app->session->set($this->sessionPrefix . $key, $value);
    }
}
0
zibra

Pourrait aider quelqu'un qui utilise Javascript Helper dans le frontal pour authentifier l'utilisateur et dans PHP, on tente d'extraire access_token de Redirect Login Helper. Alors utilisez ce qui suit

getJavaScriptHelper();

au lieu de

getRedirectLoginHelper();
0
makki

Pour moi, définir l'état de la session a fonctionné

Code complet (dans l'URL de redirection php) 

$accessToken = '';

$helper = $fb->getRedirectLoginHelper();

if(isset($_GET['state'])){

    $_SESSION['FBRLH_state']=$_GET['state'];
}


try {
    $accessToken = $helper->getAccessToken();
} catch ( Facebook\Exceptions\FacebookResponseException $e ) {
    // When Graph returns an error
    echo 'Graph returned an error: ' . $e->getMessage();

}
0
digitalzoomstudio

C’est un problème courant auquel de nombreuses personnes sont confrontées dans FB Api. ce n'est qu'un problème de SESSION. Pour résoudre ce problème, ajoutez du code tel que.

Sur le script de rappel habituellement fb-callback.php ajoute "session_start ();" juste avant d'inclure le fichier de chargement automatique de facebook. et ensuite "$ _SESSION ['FBRLH_state'] = $ _ GET ['state'];" après le "$ helper = $ fb-> getRedirectLoginHelper ();" ligne. 

Exemple : 

<?php 
session_start();
include 'vendor/autoload.php';
include 'config.php'; /*Facebook Config*/
$helper = $fb->getRedirectLoginHelper();
$_SESSION['FBRLH_state']=$_GET['state'];
try {
  $accessToken = $helper->getAccessToken();
} ?>

SOLUTION POUR PROBLÈMES INTERMITTENTS

J'étais a) redirigé vers le lien de connexion Facebook, b) redirigé de login.php vers main.php. Les utilisateurs se rendaient sur le fichier main.php et sur quelques autres pages, puis revenaient en arrière dans le navigateur.

Finalement, ils allaient frapper login.php avec un tas de créations postées, mais Facebook supprime le $ _SESSION ['FBRLH_state'] après un seul succès, donc même s'il avait le bon $ _GET ['state'], erreur sur.

La solution consiste à: a) suivre en interne si l'utilisateur est connecté et éviter la répétition de la logique Facebook dans login.php, OR b) garder une trace de tous les paramètres d'état récemment valides pour cet utilisateur particulier (éventuellement dans une session) qui ont été définis par Facebook et si le $ _GET ['state'] est dans ce tableau, alors procédez comme suit:

$ _SESSION ['FBRLH_state'] = $ _GET ['state'];

Dans ce cas, vous pouvez le faire en toute sécurité sans casser la protection CSRF.

0
Phyllis Sutherland

J'ai eu la même erreur, parce que j'ai oublié d'ajouter "www." à l'adresse de l'expéditeur. Le paramètre Client-OAuth doit contenir le nom correct. 

0

L'erreur est déclenchée si le nom d'hôte d'origine est différent du nom d'hôte cible [comme mentionné par Souch]. Lorsque les visiteurs tapaient dans la zone d'adresse URL " http://website.com ", cela diffère de " http://www.website.com ". Nous les redirigeons vers l'URL correcte en ajoutant les codes suivants en haut de la page avant session_start ().

  if($_SERVER['HTTP_Host']!=='www.website.com'){
  header('location: http://www.website.com');
  }
0
Piya Poonsawat