如何防止 PHP 会话在不同的 Apache 虚拟主机之间共享?
我在 Apache 2.2 上设置了不同的虚拟主机,一切正常,直到我意识到 PHP 会话是默认共享的。
编辑也是您始终应该设置 session_save_path ( http://php.net/manual/en/function.session-save-path.php ) 或使用数据库会话处理 ( http://php.net/manual /en/class.sessionhandler.php)如果您在共享虚拟主机上。有人可以在该站点上创建一个会话 id 并将其 chmod 为 777 并在您的站点上使用该会话 id 绕过登录/或获得更多权限。它也可以用于 SQL 注入。
这是有效的,因为 PHP 不强制执行哪些会话 ID 属于哪个站点。我知道这一点是因为我已经分析了 PHP 会话背后的 C/C++ 源代码,并且因为我想知道这怎么可能。所以永远不要太相信$_SESSION
数组在共享虚拟主机上是安全的,你不能在 SQL 查询中安全地使用这个值。
来自 C 函数的 PHP 中的一些代码(文件 session.c)php_session_start()
;是的,当您从 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>
如果您的浏览器跨域发送 cookie,则您的浏览器出现了严重问题。
当然,使用默认会话处理程序的两个虚拟主机都会将它们的会话文件写入同一个目录 - 只需在 Apache 虚拟主机配置中覆盖它:
<VirtualHost a.example.com>
...
php_value session.save_path "2;/var/www/a.example.com/data"