这是PHP Sessions across sub domains的补充 我尝试了那个问题所指出的内容,我发现问题没有给出。
所以我需要跨子域进行会话(www.example.com
到forum.example.com
)
我在www.example.com
上所做的是
session_name("a_name");
session_set_cookie_params(0, '/', '.example.com');
session_start();
echo session_id();
$_SESSION['test'] = 123;
在forum.example.com
session_name("a_name");
session_set_cookie_params(0, '/', '.example.com');
session_start();
echo session_id();
print_r($_SESSION);
session_id完全相同,但$ _SESSION不输出任何内容
如何forum.example.com
输出123
?
我尝试了session.cookie_domain = .example.com
但没有改变任何内容
当我继续forum.example.com
时,它会破坏www.example.com
个会话,并且它会以相反的方式执行相同操作,就好像它检测到它来自另一个子域并为了安全而删除所有内容。
这2个子域位于同一个Debian服务器上
我注意到的另一件事是,当我设置session_name
session_set_cookie_params
和session.cookie_domain
,它仍然具有完全相同的session_id
谢谢
答案 0 :(得分:2)
好的,我已经考虑了一段时间,我想我已经得到了它。
首先要做的事情是:由于您从两个服务器获得相同会话ID,我们可以排除任何与Cookie相关的问题。显然,您已在a_name
上成功创建了名为www.example.com
的Cookie(虽然我recommend only alphanumeric characters for that cookie name},并成功在a_name
上阅读了forum.example.com
个Cookie。但是,就像你说的那样,你没有从forum.example.com
获得任何数据。 session.cookie_lifetime = 0
不是问题:这只意味着session cookie remains until the browser is closed。
我们应该深入研究PHP的会话处理。您使用session_id()
读取的会话ID是指服务器上的文件。通常,该文件存在于/tmp/sess_$session_id
中。该文件的内容是您的$_SESSION
数组,已序列化。 (请记住,PHP中的serialize()
数据为not serialized the same way ......但现在这并不重要。)。
我认为这是与文件许可相关的问题:
/tmp/sess_$session_id
文件已设置为www.example.com
的用户和组。forum.example.com
尝试打开/tmp/sess_$session_id
,但没有适当的权限。print_r($_SESSION);
<强>解决方案强>:
检查服务器的配置文件,确保www.example.com
和forum.example.com
作为同一用户和组运行。这很关键!对于Apache,找到您的* .conf文件:
User youruser
Group yourgroup
对于nginx,找到nginx.conf:
user youruser yourgroup;
如果无法更改服务器配置文件,则应确保运行这两个站点的用户位于同一组中。
首先在服务器的shell中通过SSH加载www.example.com
然后sudo ls -ltc sess_*
来验证这是否是问题(找到sess_
后面的$session_id
) 。接下来,再次加载forum.example.com
,然后再加载sudo ls -ltc sess_*
,以查看用户和/或组的更改。
答案 1 :(得分:1)
对于这个答案,我做了一些假设:
对于我的例子,我将使用一个数据库,因为它是我所提出的想法,而不是数据库/文件访问技术,我将删除不必要的行,IE:如何连接到数据库。
如果这个概念是您所追求的,或者如果其他人希望我填写空白以获得完整性,请发表评论。随着代码。
我会采取完全不同的方法。
根据我从您的问题收集的内容以及您链接到的相关帖子,您尝试使用公共会话名称共享会话。
class MySessionHandler implements SessionHandlerInterface
最初的想法 - 不会详细介绍,仅供参考。
class MySessionHandler implements SessionHandlerInterface {
private $savePath;
public function read($id) {
$id = some_user_authentication_function();
$hash = $_COOKIE['_h'];
$result = mysql_query("SELECT sess_data FROM login_table WHERE user_id = {$id} AND hash = {$hash}");
return $result['sess_data'];
}
public function write($id, $data) {
$id = some_user_authentication_function();
$hash = $_COOKIE['_h'];
$result = mysql_query("UPDATE login_table SET sess_data = {$data} WHERE user_id = {$id} AND hash = {$hash}");
return ($result === false) ? false : true;
}
}
$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();
class customSessionHandler
{
private $hash;
private $id;
private $sess_db;
public function __construct($db) {
$this->hash = $_COOKIE['hash'];
$this->id = some_user_authentication_function($this->hash);
$this->sess_db = $db;
}
public function get($key) {
$query =
"SELECT value ".
"FROM ".$this->sess_db.
"WHERE user_id = {$id} ".
" AND hash = {$hash} ".
" AND key = {$key}";
$result = mysql_query($query);
return $result['key'];
}
public function set($key, $val) {
$query =
"REPLACE INTO ".$this->sess_db.
"SET {$key} = {$val} ".
"WHERE user_id = {$id} ".
" AND hash = {$hash}";
return (mysql_query($query) === false) ? false : true;
}
}
$handler = new customSessionHandler('sess_data');
session_start();
如开头所述,任何对解释概念不重要的代码都已被删除
对每个人来说可能并不明显的事情:
- $ key和$ val需要在发送到数据库之前进行清理。 (防止注射攻击)
- 哈希被发送到您的登录功能,因此哈希可以用于在需要时清除会话数据,也可以用于用户的身份验证。
- mysql预处理语句在这里是理想的,所以你可以在构造函数中准备两个查询,然后你只需要在每次调用时重用该语句。然后将连接关闭代码放在析构函数中。
思考后
如果每个站点都有自己的哈希值,那么安全性会更高
然后,如果您检测到安全异常,则可以阻止或重新请求来自一个站点的凭据,而不会损害站点网络的哈希值。
要实现这一点就像设置另一个包含以下内容的表一样简单:
- 用户身份
- site_name(example.com)
- 哈希
- 超时
- 重新认证
并修改session_data表,而不是访问$ key =&gt; $ hash by hash,你可以通过user_id访问它
感谢阅读,希望它对某人有用。