web-dev-qa-db-ja.com

Facebook SDKはエラーを返しました:クロスサイトリクエストフォージェリの検証に失敗しました。 URLとセッションの「状態」パラメーターが一致しません

私はこのようなPHP SDKを使用してFacebookユーザーIDを取得しようとしています

$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;

しかし、それは私にこのエラーを与えます:

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

私はphpとFacebook sdkの新しいヘルプを前もって助けてください。

56
Fadi

ログインURLを生成する前にPHPセッションを有効にし、Facebookが最終的にリダイレクトするスクリプトの先頭である限り、Cookieを設定しなくても単独で正常に動作することがわかりました( ale500の回答による )。これは5.1バージョンのSDKを使用しています。

両方のスクリプトの上部に、次を追加しました...

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

...そしてそれは「うまくいった」。

これが私にとってうまくいった最低限の完全な例です:

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());
}

どうして?

追加のメモとして、これはリポジトリのドキュメントで説明されています。 このページ の警告を見てください。

警告:FacebookRedirectLoginHelperは、セッションを使用してCSRF値を保存します。 getLoginUrl()メソッドを呼び出す前に、セッションが有効になっていることを確認する必要があります。これは通常、ほとんどのWebフレームワークで自動的に行われますが、Webフレームワークを使用していない場合は、session_start()を追加できます。 login.phpおよびlogin-callback.phpスクリプトの先頭へ。デフォルトのセッション処理を上書きできます-以下の拡張ポイントを参照してください。

独自のセッション管理を実行している場合、または複数のWebサーバーを並行して実行している場合に留意することが重要であるため、このメモを追加しています。そのような場合、PHPのデフォルトのセッションメソッドに依存することが常に機能するとは限りません。

95
enobrev

このコードを$ helper = $ fb-> getRedirectLoginHelper()の後に挿入します。

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

すでに述べた多くの素晴らしい答え、ここに私のために助けたものがあります、

問題はクロスサイトリクエストフォージェリの検証に失敗しました。FBのコードに必要なパラメーター「状態」がありませんであり、ここに解決策があります。

この行の後

$helper = $fb->getRedirectLoginHelper();

以下のコードを追加し、

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

Symfony2でFacebook SDKを使用しているときに、テンプレートのAPIからのデータを表示するTwig拡張機能を記述しているときにこのエラーが発生しました。

私にとっての解決策は、Facebookオブジェクトの設定に'persistent_data_handler'=>'session'を追加することで、メモリではなくセッションキーに状態データを保存しました。

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

デフォルトでは、組み込みのメモリハンドラを使用していましたが、私にとっては適切に機能しませんでした。メモリハンドラーは通常のコントローラー/サービスでのみSDKを使用するときに機能するため、一部の関数はTwig拡張内から呼び出されるためです。

どうやら、getLoginUrl()を呼び出すと状態が設定され、getAccessToken()を呼び出すたびに状態が取得されます。保存された状態がnullを返した場合(データハンドラーがpersistentになっていないため)、CSRF検証チェックは失敗します。

セッションを特定の方法で処理する必要がある場合、または状態を別の場所に保存する場合は、例としてFacebookSessionPersistentDataHandlerを使用して、'persistent_data_handler' => new MyPersistentDataHandler()を使用して独自のハンドラーを作成することもできます。

20
Fx32

これは、Facebookライブラリーが、Facebookから受信した状態パラメーターを、セッションでデフォルトで設定するパラメーターと一致させることができない場合に発生します。 Laravel、Yii2、Kohanaなどの独自のセッションストレージを実装するフレームワークを使用している場合、標準のFacebookセッション実装はおそらく機能しません。

これを修正するには、フレームワークのセッションライブラリを使用してPersistentDataInterfaceの独自の実装を作成し、これをFacebook\Facebookコンストラクターに渡す必要があります。

Facebook のLaravel永続性ハンドラの例を次に示します。

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);
  }
}

コンストラクターのパラメーターの例:

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

詳細はこちら: https://developers.facebook.com/docs/php/PersistentDataInterface/5.0.

16
George

最後に、FBコードを調べたところ、問題が発見されました。

クロスサイトリクエストフォージェリの検証に失敗しました。必須パラメータ「状態」がありません

fBがログインコールバックファイルを呼び出すときの「奇妙な」理由のために、PHP変数$_SESSION['FBRLH_state']が原因で同様のことが起こります。

それを解決するために、関数$helper->getLoginUrl(...)の呼び出し後にこの変数"FBRLH_state"を保存します。変数$_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);

そして、すべてのFBコードを呼び出す前にlogin-callback.phpで:

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時間の作業の節約に役立つことを願っています:)さようなら、アレックス。

8
ale500

私にとって問題は、スクリプトの前にセッションを実行していなかったことです。

そこで、Facebookクラスをインスタンス化する前にsession_start();を追加しました。

7
Nino Škopac

laravel 5.4で同じ問題が発生しました5.4

session_start();

スクリプトの上部。

以下にlaravelコントローラー名前空間のサンプルを示し、どのように機能するか例を示します。

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

がまだ開始されていないために問題が発生しているため、スクリプトの先頭にセッション開始を追加することにより、セッションを開始するだけです。

それが誰かを助けることを願っています。

4
usama

Facebookオブジェクトには、persistentDataHandlerと呼ばれるインスタンス変数があり、通常はFacebookSessionPersistentDataHandlerのインスタンスです。この変数には、ネイティブPHPセッションにアクセスするためのsetメソッドとgetメソッドがあります。

以下を使用してコールバックURLを生成する場合:

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

メソッドFacebookRedirectLoginHelper->getLoginUrl()は、32文字のランダムな文字列を作成し、$loginUrlに追加し、persistentDataHandlerのsetメソッドを使用して以下のコードに保存します。

$_SESSION['FBRLH_' . 'state']

後で$helper->getAccessToken();が呼び出されると、URLの状態パラメーターが同じセッションに保存されているものと比較され、CSRFが防止されます。一致しない場合、例外がスローされます。

FacebookSDKExceptionクロスサイトリクエストフォージェリの検証に失敗しました。必須パラメータ「状態」がありません。

これらすべてが言われているので、このプロセス中にネイティブPHPセッション機能が適切に設定されていることを確認する必要があります。以下を追加することで確認できます

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

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

前に

$accessToken = $helper->getAccessToken();

その32文字の文字列があるかどうかを確認します。

それが役に立てば幸い!

3
Chao Chen

Symfonyでは、セッションが管理されているため機能しません。

問題を解決するために、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);
    }

}

FBオブジェクトを作成するときは、新しいクラスを指定するだけです。

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

これは少し遅れるかもしれませんが、この問題はまだ続くので、他の人の助けになることを願っています。

私はしばらくの間この問題を抱えていましたが、さまざまなソリューションを探してみましたが、その多くはCSRFチェックを無効にします。だから、私が読んだすべてのものの後、これは私のために働いたことです。

私の理解では、リダイレクトURLがアプリの設定で設定したURLと一致しない場合にこのエラーが発生するため、問題は簡単に修正されましたが、セッションが正しく開始されないことで問題が発生することもあります。両方の問題について説明します。

ステップ1:必要なときにセッションが開始されていることを確認します。

例: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();

facebookのコールバックコードが設定とは別のファイルにある場合は、そのファイルでもセッションを開始します。

例: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 **/

さて、実際の問題を解決したもの。

ステップ3:アプリの設定でリダイレクトURLを設定します。

Facebookログインアプリの設定で、有効なOAuthリダイレクトURIに移動し、fbを指すURLを追加します。 -callback.phpファイル。

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

AND ALSO

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

次に、リダイレクトURLを次のように設定します。

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

Wwwの有無にかかわらずSERVER_NAMEを使用する理由

有効なOAuthリダイレクトURIはコード内のリダイレクトURLと一致する必要があり、アプリの設定では_のみを設定するためOAuth http://example.com/fb-callback.php としてリダイレクトし、$ redirectURLを http://example.com/fb-bacllbackとして設定します.php 一致させるために、ユーザーが http://www.example.com としてサイトに入力すると、ユーザーはFacebook SDKエラーを受け取ります:クロスサイトリクエストフォージェリの検証に失敗しました。ユーザーのURLが設定したものと完全に一致しないため、永続データに必要なパラメーター「状態」がありません。どうして?私にはおかしい考えがありません。

私のアプローチでは、ユーザーがあなたのサイトを http://example.com または http://www.example.com として入力した場合、常にあなたのものと一致しますアプリの設定でセットアップします。どうして? $ _SERVER ['SERVER_NAME']は、ユーザーがブラウザにURLを入力した方法に応じて、wwwの有無にかかわらずドメインを返すためです。

これは私の発見であり、これはCSRFチェックを削除せずに私のために働いた唯一のものであり、これまでのところ、問題はありません。

これがお役に立てば幸いです。

2
BlueSun3k1

これを行うだけで、新しい状態でセッションを設定できます

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

originホスト名が認証後のターゲットホスト名と異なる場合、このエラーが表示されます。

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

このステートメントを使用して、Webサイトの訪問者が http://www.mywebsite.com/ を使用した場合、クロスサイトエラーが発生します。

Originとターゲットのホスト名が、最終的なwwwプレフィックスを含めて正確に同じであることを確認する必要があります。

修正バージョン:

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

私のための簡単な修正。私が変更され:

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

に:

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

'www'を削除することで問題は解決しました。

1
Mathieu Wilson

私の場合、エラーをチェックし、コードを実行して解決策につながるエラーを見つけました:

date_default_timezone_set('Europe/Istanbul');

スクリプトの前。魅力のように働いた。場所の確認: timezones.europe.php

1
Roman Losev

私のために働くYii2ソリューション:

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

ユーザー認証にフロントエンドでJavascript Helperを使用しており、PHPでaccess_tokenログインヘルパーのリダイレクト。したがって、次を使用してください

getJavaScriptHelper();

の代わりに

getRedirectLoginHelper();
0
makki

私にとっては、セッション状態の設定が機能しました

完全なコード(リダイレクトURL 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

これは多くの人々がFB Apiで直面している一般的な問題です。これはセッションの問題です。この問題を解決するには、次のようなコードを追加します。

通常、コールバックスクリプトにfb-callback.phpに「session_start();」を追加しますfacebook autoloadファイルを含める直前。そして「$ _SESSION ['FBRLH_state'] = $ _ GET ['state'];」 「$ helper = $ fb-> getRedirectLoginHelper();」の後ライン。

例:

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

断続的な問題の解決策

私は、a)Facebookログインリンクにリダイレクトし、b)login.phpからmain.phpにリダイレクトしました。ユーザーはmain.phpおよび他のいくつかのページに移動し、ブラウザで戻るをクリックして戻ります。

最終的に、彼らはlogin.phpにたくさんの信任状を投稿してヒットしますが、Facebookは1回成功すると$ _SESSION ['FBRLH_state']を削除するため、適切な$ _GET ['state']があったとしてもエラーアウト。

解決策は、a)ユーザーがログインしている場合は内部的に追跡し、login.phpでのFacebookロジックの繰り返しを避ける、OR b)特定のユーザーの最近有効な状態パラメーターをすべて追跡する(セッション内)おそらく)Facebookによって設定されたもので、$ _ GET ['state']がその配列にある場合は、次のようにします。

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

この場合、CSRF保護を壊すことなく安全にこれを行うことができます。

0

「www」を追加するのを忘れたため、同じエラーが発生しました。送信者のアドレスに。 Client-OAuth設定では、正しい名前を指定する必要があります。

0

Originのホスト名がターゲットのホスト名と異なる場合、エラーがトリガーされます[Souchの言及]。訪問者がURLアドレスボックスに「 http://website.com 」と入力した場合、「 http://www.website.com 」とは異なります。 session_start()の前の最上位に次のコードを追加することにより、それらを正しいURLにリダイレクトします。

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