【问题标题】:How to prevent PHP sessions being shared between different apache vhosts?如何防止 PHP 会话在不同的 apache 虚拟主机之间共享?
【发布时间】:2013-08-18 05:51:26
【问题描述】:

如何防止 PHP 会话在不同的 Apache 虚拟主机之间共享?

我在 Apache 2.2 上设置了不同的虚拟主机,一切都运行良好,直到我意识到 PHP 会话是默认共享的。

【问题讨论】:

  • 如何创建一个令牌,一个用于主机 1,另一个用于主机 2?
  • @DarylGill 这是个好主意,但可能太多了。我想“呈现”不同版本的脚本,而更改代码并不会真正显示真实版本。而且工作量也很大;)

标签: php apache session vhosts


【解决方案1】:

如果您在共享虚拟主机上,编辑也是您始终应该设置 session_save_path (http://php.net/manual/en/function.session-save-path.php) 或使用数据库会话处理 (http://php.net/manual/en/class.sessionhandler.php) 的原因。有人可以在该站点上创建一个会话 id 并将其更改为 777 并在您的站点上使用该会话 id 绕过登录/或获得更多权限。它也可以用于 SQL 注入。

这是可行的,因为 PHP 不强制执行哪些会话 ID 属于哪个站点。我知道这一点是因为我分析了 PHP 会话背后的 C/C++ 源代码,并且我想知道这怎么可能。所以永远不要太相信$_SESSION 数组在共享虚拟主机上是安全的,而且你不能在 SQL 查询中安全地使用这个值。

来自 C 函数 php_session_start() 的 PHP 中的一些代码(文件 session.c);是的,当您从 PHP 调用 session_start() 时会调用此函数(我看到的唯一检查是在这些代码行中):

/* Check whether the current request was referred to by
 * an external site which invalidates the previously found id. */

if (PS(id) &&
        PS(extern_referer_chk)[0] != '\0' &&
        PG(http_globals)[TRACK_VARS_SERVER] &&
        zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_REFERER", sizeof("HTTP_REFERER"), (void **) &data) == SUCCESS &&
        Z_TYPE_PP(data) == IS_STRING &&
        Z_STRLEN_PP(data) != 0 &&
        strstr(Z_STRVAL_PP(data), PS(extern_referer_chk)) == NULL
) {
    efree(PS(id));
    PS(id) = NULL;
    PS(send_cookie) = 1;
    if (PS(use_trans_sid) && !PS(use_only_cookies)) {
        PS(apply_trans_sid) = 1;
    }
}

唯一的检查是HTTP Header“HTTP_REFERER”,但我们都知道它可以被伪造,所以这是“通过默默无闻的安全”。唯一安全的方法是使用session_save_path 或使用数据库会话处理程序。

要在 php.ini 中设置 session_save_path,您应该在http://php.net/manual/en/session.configuration.php 找到更多信息。

或者,如果 PHP 作为 Apache 模块运行,你可以在 vhost 容器的 htaccess 文件中配置它:

php_value session.save_path "path"

甚至更好的是每个虚拟主机的 PHPINIDir:

<VirtualHost ip>
[...]
PHPINIDir /var/www/...
[...]
</VirtualHost>

更新 [恐慌]:

我只是为这个答案添加了完整的解决方案,因为这也可能对其他人有所帮助。完整的虚拟主机设置示例:

<VirtualHost *:81>
    DocumentRoot /var/www/xxx1
    <Directory "/var/www/xxx1">
        AllowOverride All
        php_value session.save_path "/var/mysessionforproject_1"
   </Directory>
</VirtualHost>

<VirtualHost *:82>
    DocumentRoot /var/www/xxx2
    <Directory "/var/www/xxx2">
        AllowOverride All
        php_value session.save_path "/var/mysessionforproject_2"
   </Directory>
</VirtualHost>

【讨论】:

  • 但所有虚拟主机共享一个 php.ini... 还是我遗漏了什么?
  • 已更新,您可以使用每个 vhost 容器的 PHPINIDir 来配置每个 vhost 的 php ini
【解决方案2】:

如果您的浏览器跨域发送 cookie,那么它非常有问题。

当然,使用默认会话处理程序的两个虚拟主机都会将它们的会话文件写入同一个目录 - 只需在 Apache 虚拟主机配置中覆盖它:

<VirtualHost a.example.com>
    ...
    php_value session.save_path "2;/var/www/a.example.com/data"

【讨论】:

  • 这是关于会话,而不是 cookie。这不是浏览器的事情。我将不同的端口路由到不同的子文件夹。也许这就是重点。
  • 虽然在没有 cookie 的情况下实现 HTTP 会话是可能,但这是一种非常危险的做法 - 因此手册中的警告以及 URL 绑定默认情况下始终禁用。即使启用,处理程序也不会将会话 ID 附加到非本地域。
  • 也许我应该补充一点,这不是一个真正的应用程序,它只是一个脚本的各种版本的演示。这里没有什么重要的。
  • 如果您的意思是您在两个虚拟主机配置中使用相同的 FQDN 但端口不同,那么这正是它应该表现的方式。
猜你喜欢
  • 2012-04-03
  • 2021-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-26
  • 1970-01-01
相关资源
最近更新 更多