CSRF 状态令牌与提供的 FB PHP SDK 3.1.1 Oauth 2.0 不匹配

Posted

技术标签:

【中文标题】CSRF 状态令牌与提供的 FB PHP SDK 3.1.1 Oauth 2.0 不匹配【英文标题】:CSRF state token does not match one provided FB PHP SDK 3.1.1 Oauth 2.0 【发布时间】:2012-02-17 03:34:28 【问题描述】:

我的服务器日志显示“CSRF 状态令牌与提供的令牌不匹配”错误,这似乎发生在几乎每个用户身上。但是,用户已创建和/或经过身份验证,我能够检索用户信息。我正在使用带有 Apache 的 Linux 服务器。我也在使用最新的 Facebook php SDK v.3.1.1 谁能告诉我为什么会这样以及如何解决它?

【问题讨论】:

我还想补充一点,这种情况最近也开始发生在我身上。用户可以按预期使用该应用程序,但是我的见解在 2 月 14 日之后突然停止报告。通过我的日志,我看到了与您遇到的完全相同的错误。 【参考方案1】:

上周我遇到了类似的问题,并追踪到 state 字段被多次调用 getLoginUrl() 覆盖。每次调用getLoginUrl(),SDK中都会生成一个新的state令牌,并存储在$_SESSION中(只是一个随机值),所以如果调用两次,用户使用第一个链接登录,第二次调用将重置 SDK 的内部 state 令牌,您将在日志中看到此错误。

SDK 在 Facebook 授权用户并将其重定向回您的网站后返回的 URL 中查找相同的 state 令牌,如果不匹配,它将记录此错误(这里是指向 @ 987654321@).

【讨论】:

@Jakub Facebook 出于某种原因移动了存储库...更新了链接。我不再是 PHP SDK 的活跃用户,所以我不知道这是否仍然是一个问题。希望它对你有所帮助。 @chesles 还是个大问题,马上就遇到了! @chesles 请看我的回答 @JimmyKane 我在这里没有看到你的消息……是在另一个问题上吗?另外,我在找什么? @chesles 答案已被删除。检查。【参考方案2】:

在同一处理程序中检查两次令牌时,Facebook SDK 代码存在错误。

我这样编辑facebook.php的getCode函数:

protected function getCode() 
    if (!isset($_REQUEST['code']) || !isset($_REQUEST['state']) || $this->state === null) 
      return false;
    
    if ($this->state === $_REQUEST['state']) 
        // CSRF state has done its job, so clear it
        $this->state = null;
        $this->clearPersistentData('state');
        return $_REQUEST['code'];
    
    self::errorLog('CSRF state token does not match one provided.');

    return false;

为了更清楚,如果调用两次,则不会声明无效令牌。

需要明确的是,如果例如:

$facebook->getUser(); 然后在同一个处理程序 $facebook->getLogoutUrl() 然后 getCode() 被调用两次,从而导致错误消息无效

【讨论】:

如果有人想合并它,还有一个拉取请求可以解决这个问题:github.com/facebook/facebook-php-sdk/pull/122 作为第二条评论保留此代码。虽然 fb repo 中的合并再次被覆盖,但还有另一个提交被拒绝【参考方案3】:

好吧,我曾经遇到过这个确切的问题,我遇到了 URL 中的 statecode 参数的问题 - 我的 .htaccess 文件没有转发它们。

我猜你也有同样的问题。

CSRF state token does not match one provided

希望对你有帮助

【讨论】:

@codecowboy 这个问题的具体解决方法取决于你的重写规则。主要是,确保您传递查询字符串参数。【参考方案4】:

在 chesles 的回答中添加一点,如果您像我一样使用 session_start() - session_write_close() 函数,则可能会出现此问题。

如果在您请求 loginUrl 时没有启动会话,您将收到此错误。

旁注:为什么要停止会话?

使用会话的脚本会相互停止,因为它们正在等待会话数组可供使用。

假设您有一个流行的应用程序,有成千上万的用户,并且有一个动作(一个 php 脚本),您可以在其中发布图片。 像这样的:

--在脚本顶部开始会话

--连接脸书

--创建图像

--通过api调用共享图片

--脚本结束,会话自动关闭

这样做,会话将被脚本无缘无故地使用很长时间。 小心此类脚本,请改用以下内容:

--在创建 facebook 对象之前开始会话

--连接脸书

--用 session_write_close() 关闭会话,会话数组可用,其他脚本可以加载

--创建图像

--通过 api 调用共享图像 /* 它认为这不需要会话。 */

--脚本结束,会话已经手动关闭。

干杯。

【讨论】:

【参考方案5】:

还有一个注意事项 - 尽管 Facebook PHP API 文档中没有说明,但您必须为 PHP 会话配置 apache 才能使登录过程正常工作。这就是我们在获得“CSRF 状态令牌与提供的令牌不匹配”时遇到的问题。

确保您使用的服务器池已设置为使用 memcache 获取会话信息,否则 apache 将在本地写入会话信息,如果下一个请求没有发送到同一台服务器,您将获得“CSRF 状态令牌与提供的不匹配”。

这是在开发环境(使用一台服务器)中发挥作用的魅力之一,但在生产环境中却失败了。

我们还必须重新配置 CDN 设置以确保我们通过 PHP 会话 cookie。

【讨论】:

【参考方案6】:

我有同样的问题。这很容易。不要打电话

$fbLoginUrl = $facebook->getLoginUrl(...);

之前

$fbUser = $facebook->getUser();

否则您将收到“CSRF 状态令牌与提供的一个不匹配”错误。

【讨论】:

【参考方案7】:

我在本地机器上遇到了同样的问题,问题原来是我的 hosts 文件 阻止了与 Verisign 的通信,因此 Facebook 尝试与之通信的 URL (http://crl.verisign.com/pca3.crl) 从来没有工作(状态:404)。

从我的 hosts 文件中注释掉各种 Verisign IP 地址就可以了!

【讨论】:

【参考方案8】:

使用本地会话检查 CSRF 状态和代码,我打赌您需要检查 php.ini 中的 session.save_handler,以及它是否正常工作。

【讨论】:

【参考方案9】:

如果您在页面上使用 .htaccess mod rewrite 重定向,请在行尾使用 [QSA](查询字符串附加)来保留 GET 变量,否则您会丢失 $code 变量,这是必需的脸书登录

【讨论】:

以上是关于CSRF 状态令牌与提供的 FB PHP SDK 3.1.1 Oauth 2.0 不匹配的主要内容,如果未能解决你的问题,请参考以下文章

FB PHP SDK 将未读消息状态更改为已读和计数未读消息

使用 php sdk 在 facebook 中获取访问令牌时出错

过滤 CSRF 令牌以防止 CSRF

FB iOS SDK 3.2:为啥我需要访问令牌来记录转换像素?

Facebook SDK - 以编程方式获取访问令牌

Facebook SDK错误'必需'app_id“密钥未在配置中提供