我正在使用Facebook的服务器端用户身份验证来尝试将用户登录到我们的网站。为了防止CSRF,Facebook建议创建一个随机会话状态变量,将其传递给FB,然后FB将其传回以比较值以确保没有安全问题。这似乎在除Firefox之外的所有浏览器中都能正常工作。 Firefox正在发送状态变量,但它不会在返回到站点时存储它。 session_start()出现在文档的顶部,下面没有引用,因为出于安全原因我删除了一些变量和其他代码。
if(empty($code)) {
$rand = md5(uniqid(rand(), TRUE)); // CSRF protection
$_SESSION['mbny_state'] = $rand;
$dialog_url = "https://www.facebook.com/dialog/oauth?client_id="
. $app_id . "&redirect_uri=" . urlencode($my_url) . "&state="
. $_SESSION['mbny_state'] . "&scope=publish_stream,user_birthday,user_hometown,email";
header('Location: ' . $dialog_url);
}
$state = $_REQUEST['state'];
$secret_state = $_SESSION['state'];
// Check session state to prevent hacking
if($secret_state == $state) {
$token_url = "https://graph.facebook.com/oauth/access_token?"
. "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url)
. "&client_secret=" . $app_secret . "&code=" . $code;
$response = file_get_contents($token_url);
$params = null;
parse_str($response, $params);
// store the access token for future requests
$_SESSION['access_token'] = $params['access_token'];
// define graph url allowing us to communicate with FB with user's account
$graph_url = "https://graph.facebook.com/me?access_token="
. $params['access_token'];
$user = json_decode(file_get_contents($graph_url));
}
else {
$error_message = 'An error has occurred. Your session ID does not match. Please exit and try again.<br /><br />' . $secret_state . ' :: ' . $state . ' :: ' . $_SESSION['test'];
}
Firefox将其显示给显示错误消息的else。我稍后在文档中返回了$ _SESSION ['state']的值,它现在为NULL。
此外,我在会话中添加了一个名为test的测试变量,它被Firefox存储得很好。我错过了什么?
提前致谢。
编辑:好像Firefox愿意在if语句之外存储会话变量。如果我在if语句之前设置$ _SESSION ['myny_state'],它会在FB返回$ code时存储该值。这里的问题是状态肯定不匹配,因为它现在正在重置每个页面调用,因为它在if语句之外。
我们说话的时候,我正在失去头发。答案 0 :(得分:4)
在密切关注Firefox中发生的事情之后,我注意到Firefox正在从域名中删除“www”,即使该地址最初包含“www”。然后会话被保存到http://domain.com/whatever,而Facebook应用程序将用户重定向回http://www.domain.com/whatever。
有两种方法可以解决这个问题。我选择使用.htaccess重写条件解决这个问题:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^domain.com [NC]
RewriteRule ^(.*)$ http://www.domain.com/$1 [L,R=301]
这也可以通过设置session.cookie_domain来实现,如下所示:
ini_set('session.cookie_domain', '.domain.com');
希望有人觉得这很有用。也许它可以节省你五个小时的调试实际上没有bug的东西。
作为旁注,它被认为是一种良好的搜索引擎优化实践,强制您的网站使用www或没有www - 而不是两者。
答案 1 :(得分:3)
$_SESSION
vars存储在服务器端,而不是客户端。
session_start()
吗?因为它不在您引用的代码中。PHPSESSID
设置cookie以将客户端浏览器与服务器的会话数据连接。Facebook可能正在剥离你的状态变量,因为它不是urlencoded。尝试更换:
urlencode($my_url) . "&state=" . $_SESSION['state']
使用:
urlencode($my_url . "&state=" . $_SESSION['state'])
答案 2 :(得分:1)
如果这是您的完整代码,则必须在顶部或开始使用会话变量之前添加session_start();
。
此外,您需要在要添加/检索数据的所有网页上添加session_start();
。
答案 3 :(得分:0)
有时重新启动Firefox浏览器可以解决问题。我不知道为什么,但它确实有效。