web-dev-qa-db-ja.com

Facebook PHP SDK 5 :: API 2.4 ::クロスサイトリクエストフォージェリの検証に失敗しました。必須パラメーター "state"がありません

Facebook経由でログインしてaccessTokenを取得しようとするために、非常に簡単なPHPスクリプトを実行しました。しかし、次のコードを実行しようとすると、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="' . $loginUrl . '">Log in with Facebook!</a>';
    }

}

exit;
12
Éric Senterre

一部のサーバーでこの行を追加する必要がありました。

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

サーバー構成によっては、このエラーがランダムに発生します。

23
M.Dalda

両方のスクリプトの先頭にあるsession_start()。私はここから解決策を得ました: https://github.com/facebook/facebook-php-sdk-v4/issues/47

9
Ruhul Amin

サイトの「www」バージョンを使用してログインリンクを生成している場合に、www以外のバージョンにリダイレクトされると、セッションで問題が発生します。したがって、サイトのwwwバージョンにアクセスし、同じwwwバージョンにコールバックURLを定義してください。また、サーバー構成で永続的なリダイレクトを定義して、非wwwバージョンからサイトにアクセスするすべてのユーザーがwwwバージョンにリダイレクトされるようにすることもできます。

9
che-azeh

私も同じ問題に遭遇し、stackoverflow puting lineについて調査した後

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

上記は私の問題を解決しました

$helper = $fb->getRedirectLoginHelper();  
3
ashutosh

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

通常、コールバックスクリプトにfb-callback.phpに「session_start();」を追加しますfacebook autoloadファイルをインクルードする直前。そして「$ _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();
} ?>
2
Ricky Harerri

トークンを取得する前に[PersistentDataHandler]を明示的に設定すると、リクエストが成功することが保証されます。以下は、$ _ GET ['state']を取得し、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'));
2
Dan Baddeley

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

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

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

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

修正バージョン:

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

私は同様の問題に遭遇し、Nanan Koesharwantoの解決策を見つけました。ベンダーディレクトリ内のソースファイルを変更することは非常に悪い考えであるため、それは奇妙なものに似ています。だからここにトリックがあります。

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

失敗した場合は、use Session;コントローラーで。

1
Rajender Joshi

SymfonyでFacebook PHP SDKを使用してFacebookログインを実装しようとしましたが、同じエラーが発生しました "クロスサイトリクエストフォージェリの検証に失敗しました。 「行方不明」

FacebookのPersistentDataInterfaceを実装するカスタムハンドラーでFacebookアプリのインスタンス化にpersistent_data_handlerパラメーターを追加することで問題を解決しましたPHP SDK。

魅力のように機能します。

public function facebookCallbackAction(Request $request) {
    $session = $request->getSession();

    $fb = new \Facebook\Facebook([
        'app_id' => $this->container->getParameter('facebook_app_id'),
        'app_secret' => $this->container->getParameter('facebook_app_secret'),
        'default_graph_version' => 'v2.5',
        'persistent_data_handler' => new SymfonyPersistentDataHandler($session),
    ]);
}

私のカスタムハンドラー:

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

class SymfonyPersistentDataHandler implements PersistentDataInterface {
    protected $session;
    protected $sessionPrefix = 'FBRLH_';

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

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

    public function set($key, $value) {
        $this->session->set($this->sessionPrefix . $key, $value);
    }
}
1
Julien F.

Laravel 5.2

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

そして this 時間を読んだ後。ベンダースクリプトを変更しようとしました。

123行目の_vendor\facebook\php-sdk-v4\src\Facebook\Helpers\FacebookRedirectLoginHelper.php_で、このスクリプトを変更します。

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

into(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.');
    }
}
_

それが私がしたことのすべてです。エラーはなくなりました。

1

私にとっては、これを追加してセッションを開始するだけで問題は解決しました:

session_start();

両方のファイルの先頭(facebook urlおよびコールバックファイルを生成する最初のファイル:login.phpおよびfb-callback.php( https://developers.facebook.com/docs/php/howto/example_facebook_login ))。

私もこれを追加する必要がありました:

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

上部にある別の無関係なエラーを防止します。

1
Adam Tong

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

ネイティブPHPセッション機能が適切に設定されていることを確認する必要があります。

1
Chao Chen

最後に、FBコードを調べたところ、「クロスサイトリクエストフォージェリの検証に失敗しました。必要なパラメータ「状態」が見つかりません」などの問題は、PHP variable $ _SESSION ['FBRLH_state' ] FBがログインコールバックファイルを呼び出すときの「奇妙な」理由のため。

それを解決するために、関数$ 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 session so ..

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

この回答が8〜10時間の作業の節約に役立つことを願っています:)さようなら、アレックス。

0
ale500

ここでの実際の問題は、PHPファイルのエンコードです。UTF8を使用しましたが、BOMなしのUTF8でなければなりませんでした。

間違ったエンコーディングの副作用は、SESSIONが適切に機能しなかったことで、SDKは適切に機能するために必要な情報を取得できませんでした。

適切に構成されたエラー報告は、問題がまっすぐにあったことを伝えていたでしょう。

「noob」カテゴリでこのバグを埋めることができると思います。しかし、それでも、私のような他の初心者にとっては役立つと思います。

0
Éric Senterre

Session_start()で問題が解決しない場合は、Facebook開発者アプリの有効なOAuthリダイレクトURIに間違ったURIを挿入します。

解決するには:まず、fb-callback.phpに移動し、ヘッダー関数に配置したURIを見つけます。例:header( "Location: https://localhost/home.php ")。次に、Facebook開発者アプリに移動し、サイドバーで、[製品]タブの下にある[Facebookログイン]をクリックし、[設定]をクリックします。 Valid OAuth Redirect URIs)で、ヘッダーに追加したURIを追加します。この例では、 https://localhost/home.php を追加します。

お役に立てれば。

スクリプトを実行する前にセッションが開始することを確認する必要があります。ただし、同じスクリプトでセッションを再度開始すると、再び_443: Network is unreachable_がスローされます。これが何らかの助けになることを願っています。

if (session_status() == PHP_SESSION_NONE){ session_start(); }を使用しました

0
Tharindu

Cakephp 3.xを使用していて、この問題があり、解決方法がわからない場合は、 session_start();を追加しますauthおよびコールバックメソッドの最初に。

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

私が修正したのは、'secure' => trueからconfig/session.phpのfalseへ。そもそもhttpsを使用していないときに、誤ってこれをtrueに設定していました。

0
Jonas Menk

私にとって、これは'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'
  ]);
0
Amit Tyagi

私にとって解決策は、名前空間のFacebook\Exceptions\FacebookSDKExceptionExceptionに置き換えることで例外をキャッチすることでした。スクリプトが既に例外を使用しているためです。

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;
}
0
michalzuber