跨子域的PHP会话2

时间:2012-03-08 04:33:26

标签: php session cross-domain debian

这是PHP Sessions across sub domains的补充 我尝试了那个问题所指出的内容,我发现问题没有给出。

所以我需要跨子域进行会话(www.example.comforum.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_paramssession.cookie_domain,它仍然具有完全相同的session_id

谢谢

2 个答案:

答案 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 ......但现在这并不重要。)。

我认为这是与文件许可相关的问题:

  1. /tmp/sess_$session_id文件已设置为www.example.com的用户和组。
  2. forum.example.com尝试打开/tmp/sess_$session_id,但没有适当的权限
  3. 因此,您在尝试print_r($_SESSION);
  4. 时获得空结果

    <强>解决方案
    检查服务器的配置文件,确保www.example.comforum.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)

对于这个答案,我做了一些假设:

  • 用户必须在每个域上至少输入一次凭据(任何其他方式都是严重的安全问题)
  • 您可以访问Web根目录之外的数据库或文件空间。
  • 子域名,域名或任何其他名称将被引用为“site”
  • 目标是从每个站点/域访问一个公共文件(物理文件或在数据库中序列化)。

对于我的例子,我将使用一个数据库,因为它是我所提出的想法,而不是数据库/文件访问技术,我将删除不必要的行,IE:如何连接到数据库。

如果这个概念是您所追求的,或者如果其他人希望我填写空白以获得完整性,请发表评论。随着代码。


我会采取完全不同的方法。
根据我从您的问题收集的内容以及您链接到的相关帖子,您尝试使用公共会话名称共享会话。

  1. 每个网站都有自己的会话ID。
  2. 每个网站都有自己的身份验证Cookie($ _COOKIE ['userid']或$ _COOKIE ['userhash'])。
  3. 创建单个会话,并在每个站点上存储公共cookie。
    • 使用自定义会话处理程序,每个站点都会读取相同的数据。 class MySessionHandler implements SessionHandlerInterface
    • 我的思想是一个更简单的方法,一个类似于会话处理程序,读/写一个公共文件的类。由于php的会话处理程序在脚本结束之前不保存数据
  4. 最初的想法 - 不会详细介绍,仅供参考。

    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访问它

    感谢阅读,希望它对某人有用。