Facebook PHP SDK 5 :: API 2.4 :: Проверката на фалшифицирането на междусайтови заявки е неуспешна. Липсва задължителен параметър

Направих много прост PHP скрипт, само за да се опитам да вляза през Facebook и да получа accessToken. Но когато опитам следния код, получавам изключение от комплекта за разработване на софтуер (SDK): «Неуспешно валидиране на фалшификация на заявка между сайтове. Липсва задължителният параметър „състояние“. ».

Ето моят код:

require_once __DIR__ . '/facebook-sdk-v5/autoload.php';
session_start();

$fb = new Facebook\Facebook([
    'app_id' => '{my-own-app-id}',
    'app_secret' => '{my-own-app-secret}'
]);

// Check to see if we already have an accessToken ?
if (isset($_SESSION['facebook_access_token'] )) {
    $accessToken = $_SESSION['facebook_access_token'];
    echo "Horray we have our accessToken:$accessToken<br />\n";

} else {
    // We don't have the accessToken
    // But are we in the process of getting it ? 
    if (isset($_REQUEST['code'])) {
        $helper = $fb->getRedirectLoginHelper();
        try {
            $accessToken = $helper->getAccessToken();
            } 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)) {
              // Logged in!
              $_SESSION['facebook_access_token'] = (string) $accessToken;

              // Now you can redirect to another page and use the
              // access token from $_SESSION['facebook_access_token']

              echo "Finally logged in! Token:$accessToken";
        }           
    } else {
        // Well looks like we are a fresh dude, login to Facebook!
        $helper = $fb->getRedirectLoginHelper();
        $permissions = ['email', 'user_likes']; // optional
        $loginUrl = $helper->getLoginUrl('http://mywebsite.com/myapp/index.php', $permissions);

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

}

exit;

person Éric Senterre    schedule 20.07.2015    source източник
comment
Проверете дали вашата PHP сесия работи правилно (подаване на идентификатора на сесията.)   -  person CBroe    schedule 21.07.2015
comment
Това и направих. И накрая открих, че моят PHP файл е кодиран в UTF8 вместо UTF8 без BOM. Благодаря за вашата помощ.   -  person Éric Senterre    schedule 21.07.2015


Отговори (23)


Трябваше да добавя тези редове в някои сървъри:

$helper = $fb->getRedirectLoginHelper();
if (isset($_GET['state'])) {
    $helper->getPersistentDataHandler()->set('state', $_GET['state']);
}

Получавам тази грешка на случаен принцип, в зависимост от конфигурацията на сървъра.

person mdalda    schedule 04.08.2016
comment
От часове се боря с този проблем и това е единственото решение, което работи за мен. Мерси човече! - person grpaiva; 26.10.2016
comment
Работи като чар. Това е най-добрият отговор. Благодаря ти - person Duy Hoang; 13.02.2017
comment
Не прави това! Това ефективно заобикаля проверката на CSRF. - person tomasbedrich; 25.07.2017

session_start() в началото на двата скрипта. Получих решение от тук: https://github.com/facebook/facebook-php-sdk-v4/issues/473

person Ruhul Amin    schedule 08.02.2016

Ако използвате „www“ версия на вашия сайт за генериране на връзката за вход и бъдете пренасочени към версията без www, ще срещнете проблеми със сесията си. Затова се уверете, че имате достъп до www версията на вашия сайт и след това дефинирайте URL адреса за обратно извикване към същата www версия. Освен това можете да дефинирате постоянни пренасочвания в конфигурацията на вашия сървър, за да сте сигурни, че всеки, който има достъп до вашия сайт от не-www версията, ще бъде пренасочен към www версията или обратно.

person Cedric Ipkiss    schedule 27.10.2015

Аз също се сблъсках със същия проблем и след проучване на stackoverflow putting line

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

по-горе реши проблема ми

$helper = $fb->getRedirectLoginHelper();  
person ashutosh    schedule 14.09.2016
comment
Имайте предвид, че това решение заобикаля CSRF проверка, въведена от API. - person Phyllis Sutherland; 29.09.2017

получавате тази грешка, ако вашето първоначално име на хост е различно от целевото име на хост, след като бъде удостоверено.

$loginUrl = $helper->getLoginUrl('http://mywebsite.com/myapp/index.php', $permissions);

с това изявление, ако посетителят на уебсайта Ви е използвал http://www.mywebsite.com/ кръстосаното грешка на сайта ще бъде повдигната.

Трябва да се уверите, че първоначалното и целевото име на хост са напълно еднакви, включително евентуалния префикс www.

Фиксирана версия:

$loginUrl = $helper->getLoginUrl('http://'.$_SERVER['SERVER_NAME'].'/myapp/index.php', $permissions);
person Jean.R    schedule 03.01.2016

Laravel 5.2

Имам и тази грешка „Неуспешно валидиране на фалшификация на заявка между сайтове. Липсва задължителен параметър „състояние“.

и след като четете това в продължение на часове. Опитах се да променя скрипта на доставчика.

в vendor\facebook\php-sdk-v4\src\Facebook\Helpers\FacebookRedirectLoginHelper.php на ред 123 променям този скрипт:

private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
{
    $state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
    $this->persistentDataHandler->set('state', $state);

    return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
}

в (добавям Session::put('state', $state);)

private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
{
    $state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
    $this->persistentDataHandler->set('state', $state);
    Session::put('state', $state);
    return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
}

и на ред 234 променям този скрипт:

protected function validateCsrf()
{
    $state = $this->getState();
    $savedState = $this->persistentDataHandler->get('state');

    if (!$state || !$savedState) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
    }

    $savedLen = strlen($savedState);
    $givenLen = strlen($state);

    if ($savedLen !== $givenLen) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }

    $result = 0;
    for ($i = 0; $i < $savedLen; $i++) {
        $result |= ord($state[$i]) ^ ord($savedState[$i]);
    }

    if ($result !== 0) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }
}

в (добавих $this->persistentDataHandler->set('state', Session::get('state'));)

protected function validateCsrf()
{
    $state = $this->getState();
    $this->persistentDataHandler->set('state', Session::get('state'));
    $savedState = $this->persistentDataHandler->get('state');

    if (!$state || !$savedState) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
    }

    $savedLen = strlen($savedState);
    $givenLen = strlen($state);

    if ($savedLen !== $givenLen) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }

    $result = 0;
    for ($i = 0; $i < $savedLen; $i++) {
        $result |= ord($state[$i]) ^ ord($savedState[$i]);
    }

    if ($result !== 0) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }
}

това е всичко, което направих. и грешката изчезна.

person Nanang Koesharwanto    schedule 18.04.2016
comment
Твърде много за промяна. - person CodeGuru; 19.07.2016
comment
Не трябва да променяте файловете на доставчика! - person andrewtweber; 21.05.2017
comment
@andrewtweber : няма повече опции за мен, тъй като вече опитах няколко метода и това е единственият метод, който работи в моя случай. - person Nanang Koesharwanto; 25.10.2017
comment
всички знаем, че не можем да променяме файловете на доставчика, но това решение го реши! - person Leonardo Max; 20.09.2020
comment
@CodeGuru, не мисля така, защото се добавя само един ред скрипт във функцията makeUrl и един ред във функцията validateCsrf. - person Nanang Koesharwanto; 14.01.2021

Задаването на [PersistentDataHandler] изрично, преди да получите своите токени, ще гарантира, че заявката ще бъде успешна. По-долу е показано как да извлечете $_GET['state'] и просто да го инжектирате в "to be used [helper]" на Symfony 2.x | 3.x

Имах абсолютно същия проблем като O.P. и това реши проблема ми.

//create your new facebook sdk instance
$this->fb = new Facebook([
   'app_id' => $facebookAppId,
   'app_secret' =>$facebookAppSecret,
   'default_graph_version' =>$facebookDefaultGraphVersion
]);    

//retrieve the helper
$this->helper = $this->fb->getRedirectLoginHelper();

//below is the money shot
//setting this explicitly before you get your tokens will guarantee that the request will be a success. It Fetches $_GET['state'] & simply injects it into the "to be used [helper]"
$this->helper->getPersistentDataHandler()->set('state', $request->query->get('state'));
person Dan Baddeley    schedule 22.03.2017

Това е често срещан проблем, с който се сблъскват много хора във FB Api. това е проблем само със СЕСИЯ. За да разрешите този проблем, добавете код като.

В скрипта за обратно извикване обикновено fb-callback.php добавя "session_start();" точно преди да включите файла за автоматично зареждане на facebook. и след това "$_SESSION['FBRLH_state']=$_GET['state'];" след "$helper = $fb->getRedirectLoginHelper();" линия.

Пример:

<?php 
session_start(); /*Add session start*/
include 'vendor/autoload.php';
include 'config.php'; /*Facebook Config*/
$helper = $fb->getRedirectLoginHelper();
$_SESSION['FBRLH_state']=$_GET['state']; /*Add This*/
try {
  $accessToken = $helper->getAccessToken();
} ?>
person Ricky Harerri    schedule 30.05.2017
comment
Имайте предвид, че такова решение нарушава CSRF защитата. Тъй като защитата се основава на сравнение на съхранен токен и получен такъв. Предоставеният код ги принуждава да съвпадат - презаписва съхранения токен с получения. - person 3DFace; 27.07.2017

Истинският проблем тук беше кодирането на моя PHP файл. Използвах UTF8, но трябваше да е UTF8 без BOM.

Страничният ефект от грешното кодиране беше, че моята SESSION не работи правилно и след това SDK не успя да извлече необходимата информация, за да работи правилно.

Правилно конфигурирано отчитане на грешка би подсказало директно, че има проблем.

Мисля, че можем да попълним този бъг в категорията "noob". Но все пак мисля, че може да бъде полезно и на други нуби като мен.

person Éric Senterre    schedule 21.07.2015
comment
Здравей Ерик, имам същата грешка. Аз самият съм малко нуб. Кълна се, че работеше добре преди няколко дни, но сега имам същата грешка като вас. Моят доставчик работи с UTF-8 (default_charset)... искате да кажете, че това трябва да се промени на UTF8 без BOM, за да работи влизането? Благодаря - person Tatters; 21.07.2015
comment
Да, вашият PHP файл се нуждае от кодиране на UTF8 без BOM. В противен случай PHP файлът изпраща знак, преди session_start() да може да създаде своите бисквитки в HTTP заглавката (или нещо подобно). Попадам в този проблем отчасти защото съм нов потребител на Notepad++. И сляпо зададох кодирането си на UTF8, защото френските акценти не се показваха правилно на страницата ми, както правех в EditPlus. Така че основно, ДА задайте кодирането на вашия PHP файл на UTF8 без BOM. Не мога да гарантирам, че ще реши вашия проблем, но реши моя. - person Éric Senterre; 21.07.2015
comment
Хубаво, благодаря. Ще пробвам и ще видя какво ще стане. - person Tatters; 21.07.2015

За мен проблемът е решен сега просто като стартирам сесията, като добавя това:

session_start();

в началото на двата файла (първия файл, генериращ URL адрес на Facebook, и файла за обратно извикване: login.php и fb-callback.php (https://developers.facebook.com/docs/php/howto/example_facebook_login)).

Трябваше да добавя и това:

$config['app_id'] = 'myapp_id';

в горната част, за да предотвратите друга несвързана грешка.

person Adam Tong    schedule 02.01.2016

Както отговорих тук: Facebook SDK върна грешка: Неуспешно валидиране на фалшификация на заявка между сайтове. Параметърът състояние от URL адреса и сесията не съвпадат

трябва да се уверите, че вашата собствена функция за PHP сесия е правилно настроена.

person Chao Chen    schedule 22.01.2016

При мен това се случваше поради 'persistent_data_handler'. Като добавих това в конфигурацията на Facebook, успях да го накарам да работи.

session_start();
$fb = new Facebook\Facebook([
  'app_id'     => '6XXXXXXXXX',
  'app_secret' => '5XXXXXXXXXXXXXX',
  'default_graph_version' => 'v2.6', 
  'persistent_data_handler' => 'session'
  ]);
person Amit Tyagi    schedule 25.06.2016

Сблъсках се с подобен проблем и намерих решението на Nanang Koesharwanto. Това е по-скоро странност, тъй като модифицирането на изходните файлове в директорията на доставчика е много лоша идея. Така че тук е трикът.

public function callback(Request $request)
{
    $this->helper->getPersistentDataHandler()->set('state', $request->state);
    return $this->helper->getAccessToken();
}

Ако не успее, поставете use Session; във вашия контролер.

person Rajender Joshi    schedule 03.06.2016
comment
Имайте предвид, че това решение заобикаля CSRF проверка, въведена от API. - person Phyllis Sutherland; 29.09.2017

Накрая, разглеждайки кода на FB, открих, че проблемът „Потвърждаването на фалшифициране на заявка между сайтове е неуспешно. Липсва задължителен параметър „състояние“ и подобни са причинени от PHP променлива $_SESSION['FBRLH_state'], която по някаква "странна" причина, когато FB извикване на файла за обратно извикване за влизане.

За да го разреша, съхранявам тази променлива "FBRLH_state" СЛЕД извикването на функция $helper->getLoginUrl(...). Много е важно да се направи само след извикването на тази функция, тъй като е вътре в тази функция, когато променливата $_SESSION['FBRLH_state'] е попълнена.

По-долу пример за моя код в 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);

И в login-callback.php преди извикване на целия FB код:

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

Не на последно място, не забравяйте също да включите код за PHP сесия, така че..

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

Надявам се този отговор да ви помогне да спестите 8-10 часа работа :) Чао, Алекс.

person ale500    schedule 15.08.2015

трябва да сте сигурни, че сесията започва преди стартирането на скрипта. но отново ще хвърли 443: Network is unreachable, ако стартирате сесия отново на същия скрипт. надявам се това да помогне на някой.

Току-що използвах if (session_status() == PHP_SESSION_NONE){ session_start(); }

person Tharindu    schedule 24.03.2016

За тези от вас, които използват cakephp 3.x и имат този проблем и нямат представа как да го решат. Добавете session_start(); в началото на вашия метод за удостоверяване и обратно извикване.

public function Facebookauth()
{
session_start();
 $fb = new Facebook([
      'app_id' => '{app_id}',
      'app_secret' => '{app_secret}',
      'default_graph_version' => 'v2.6',
     ..........

    ]);

you can still use 
     $session = $this->request->session();
person Emastmagy MastMagy    schedule 30.05.2016

Решението за мен беше да променя 'secure' => true на false в config/session.php. Случайно бях задал това на true, докато не използвах https на първо място.

person Jonas Menk    schedule 22.07.2016

За мен решението беше улавяне на изключението чрез замяна на пространството от имена Facebook\Exceptions\FacebookSDKException само с Exception, защото скриптът вече го използваше.

use Facebook\Facebook;

// code ...

$fb = new Facebook([
    'app_id' => FB_APP_ID,
    'app_secret' => FB_APP_SECRET,
    'default_graph_version' => 'v2.5',
]);

$helper = $fb->getRedirectLoginHelper();
try {
    $accessToken = $helper->getAccessToken();
} catch (Exception $e) {
    echo $e->getMessage();
    exit;
}
person michalzuber    schedule 30.08.2016

Ако session_start() все още не решава проблема, вие сте поставили грешен URI адрес във валидния URI за пренасочване на OAuth на вашето приложение за разработчици във Facebook.

За да разрешите: Първо отидете на вашия fb-callback.php, намерете URI, който сте поставили във функцията за заглавка, например: header("Местоположение: https://localhost/home.php"). След това отидете на вашите приложения за разработчици на Facebook и след това в страничната лента щракнете върху Вход във Facebook, което е под раздела Продукти, след което щракнете върху Настройки. Във валидните URI адреси за пренасочване на OAuth добавете URI адреса, който сте поставили в заглавката. От моя пример ще поставя https://localhost/home.php.

Надявам се това да помогне.

person John Joshua Villegas    schedule 21.11.2018

Разреших тази грешка, като зададох URL адреса си за обратно повикване във „Facebook -> Вход -> Валидни URI адреси за пренасочване на OAuth“ в акаунта на програмист във Facebook.

person Tarak Gandhi    schedule 08.05.2020

Най-накрая, след всички тези хубави грешки, поправих всичките си проблеми с друго решение, примерът от документите за разработчици на Facebook е остарял.

SDK V5 и API 2.4 работи като в този урок, трябва да се дефинира маркерът за достъп

Уверете се, че сте попълнили APP-IP|APP-SECRET с вашите идентификационни данни.

Пример от урока:

$fb = new Facebook\Facebook([
      'app_id' => 'APP-ID',
      'app_secret' => 'APP-SECRET',
      'default_graph_version' => 'v2.4',
      'default_access_token' => 'APP-ID|APP-SECRET'
]);

Използвайте това, а не примера във facebook документите за програмисти.

Забавлявай се :)

person RakonDark    schedule 20.10.2015

Каквото и да правиш. Просто не извиквайте getAccessToken() повече от веднъж. Той премахва състоянието от сесия веднага щом бъде извикано.

person Jasmeet Singh    schedule 15.05.2017

person    schedule
comment
и това работи за laravel: developers.facebook.com/docs/php/PersistentDataInterface/ 5.0.0 - person Amila Dev; 13.04.2018