PHP 会话安全
Posted
技术标签:
【中文标题】PHP 会话安全【英文标题】:PHP Session Security 【发布时间】:2010-09-05 05:54:41 【问题描述】:在使用 php 维护负责任的会话安全方面有哪些指导方针?网络上到处都是信息,现在是时候将它们全部集中在一个地方了!
【问题讨论】:
【参考方案1】:一个指导原则是每次会话的安全级别更改时调用session_regenerate_id。这有助于防止会话劫持。
【讨论】:
【参考方案2】:我认为主要问题之一(正在 PHP 6 中解决)是 register_globals。目前用于避免register_globals
的标准方法之一是使用$_REQUEST
、$_GET
或$_POST
数组。
“正确”的做法是通过filters。
所以而不是:
$username = $_POST["username"];
你会这样做:
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
甚至只是:
$username = filter_input(INPUT_POST, 'username');
【讨论】:
这与问题完全没有关系。 真的吗?那么为什么在接受的答案中他们提到不使用寄存器全局变量?就大多数普通开发人员而言,注册全局变量和表单变量处理不属于“会话”的范畴,即使它在技术上不是“会话”对象的一部分?跨度> 我同意,这并没有完全回答这个问题,但它绝对是问题答案的一部分。同样,这充实了公认答案中的一个要点,“不要使用寄存器全局变量”。这告诉我们该怎么做。【参考方案3】:这非常简单明了,但请务必在每次使用后session_destroy。如果用户没有明确注销,这可能很难实现,因此可以设置一个计时器来执行此操作。
这是一个很好的tutorial setTimer() 和 clearTimer()。
【讨论】:
【参考方案4】:PHP 会话和安全性的主要问题(除了会话劫持)与您所处的环境有关。默认情况下,PHP 将会话数据存储在操作系统临时目录中的文件中。没有任何特别的想法或计划,这是一个全球可读的目录,因此您的所有会话信息对任何有权访问服务器的人都是公开的。
至于在多个服务器上维护会话。到那时,最好将 PHP 切换到用户处理的会话,它会调用您提供的函数来 CRUD(创建、读取、更新、删除)会话数据。此时,您可以将会话信息存储在数据库或类似 memcache 的解决方案中,以便所有应用程序服务器都可以访问数据。
如果您在共享服务器上,存储您自己的会话也可能是有利的,因为它可以让您将其存储在数据库中,您通常比文件系统拥有更多的控制权。
【讨论】:
【参考方案5】:我会检查 IP 和用户代理,看看它们是否改变
if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
|| $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
//Something fishy is going on here?
【讨论】:
如果用户在负载平衡的代理场后面,IP 可以合法地更改。 而且每次用户升级浏览器时,user_agent 都会发生变化。 @scotts 我同意 IP 部分,但对于浏览器升级,您将在他们登录时设置会话,所以我看不出他们如何在不创建新会话的情况下升级浏览器登录后再次。 我相信在 IE8 的兼容模式之间切换时 user_agent 也会发生变化。也很容易造假。 是的,但是那些拥有静态 IP eq GSM 并且每半小时更换一次的用户呢?因此,将 IP 存储在 Session + 主机名中,当 IP != REMOTE_ADDR 检查主机并比较主机名 eq。 12.12.12.holand.nl-> 什么时候是 holand.nl == true。但是有些主机有基于 IP 的主机名然后需要比较掩码 88.99.XX.XX【参考方案6】:根据我的经验,使用 IP 地址并不是最好的主意。例如;我的办公室有两个根据负载使用的 IP 地址,我们经常遇到使用 IP 地址的问题。
相反,我选择将会话存储在我服务器上域的单独数据库中。这样,文件系统上的任何人都无法访问该会话信息。这对 3.0 之前的 phpBB 非常有帮助(他们已经修复了这个问题),但我认为这仍然是一个好主意。
【讨论】:
【参考方案7】:如果您使用session_set_save_handler(),您可以设置自己的会话处理程序。例如,您可以将会话存储在数据库中。有关数据库会话处理程序的示例,请参阅 php.net cmets。
如果您有多个服务器,数据库会话也很好,否则如果您使用基于文件的会话,则需要确保每个网络服务器都可以访问相同的文件系统来读取/写入会话。
【讨论】:
【参考方案8】:为了确保您的会话安全,需要做几件事:
-
在对用户进行身份验证或执行敏感操作时使用 SSL。
每当安全级别更改(例如登录)时重新生成会话 ID。如果您愿意,您甚至可以在每个请求中重新生成会话 ID。
会话超时
不要使用寄存器全局变量
在服务器上存储身份验证详细信息。也就是说,不要在 cookie 中发送用户名等详细信息。
检查
$_SERVER['HTTP_USER_AGENT']
。这为会话劫持增加了一个小障碍。您还可以检查 IP 地址。但这会导致由于多个 Internet 连接上的负载平衡等原因而更改 IP 地址的用户出现问题(在我们这里的环境中就是这种情况)。
锁定对文件系统上会话的访问或使用自定义会话处理
对于敏感操作,请考虑要求登录用户再次提供其身份验证详细信息
【讨论】:
仅对某些操作使用 SSL 是不够的,除非您对加密和未加密流量有单独的会话。如果你在 HTTPS 和 HTTP 上使用单个会话,攻击者将在第一次非 HTTPS 请求时窃取它。 -1 用户代理很容易被欺骗。您所描述的内容浪费代码并且不是安全系统。 @The Rook,它可能是一个微不足道的障碍(攻击者可以使用他们自己的站点捕获受害者的用户代理)并通过默默无闻来依赖安全性,但它仍然是一个额外的障碍。如果在会话使用期间用户代理 HTTP 发生变化,这将是非常可疑的并且很可能是攻击。我从来没有说过你可以单独使用它。如果您将它与其他技术结合使用,您将拥有一个更加安全的网站。 @grom 我认为这就像在你的门上贴一块透明胶带,并说它可以防止人们闯入。 如果您正在检查用户代理,您将在 IE8 用户切换兼容模式时阻止所有请求。看看我在自己的代码中找到这个问题的乐趣:serverfault.com/questions/200018/http-302-problem-on-ie7。我正在检查用户代理,因为正如其他人所说的那样,欺骗是一件微不足道的事情。【参考方案9】:您需要确保会话数据是安全的。通过查看您的 php.ini 或使用 phpinfo() 您可以找到会话设置。 _session.save_path_ 告诉你它们的保存位置。
检查文件夹及其父文件夹的权限。它不应该是公开的 (/tmp) 或可供共享服务器上的其他网站访问。
假设你还想使用php session,你可以通过更改_session.save_path_设置php使用其他文件夹,或者通过更改_session.save_handler_将数据保存在数据库中。
您也许可以在您的 php.ini 中设置 _session.save_path_(一些提供商允许这样做),或者对于 apache + mod_php,在您站点根文件夹中的 .htaccess 文件中设置:
php_value session.save_path "/home/example.com/html/session"
。您也可以在运行时使用 _session_save_path()_ 设置它。
检查Chris Shiflett's tutorial 或Zend_Session_SaveHandler_DbTable 以设置和替代会话处理程序。
【讨论】:
【参考方案10】:This session fixation paper 有很好的指示可能攻击的地方。另见session fixation page at Wikipedia。
【讨论】:
【参考方案11】:我的两(或更多)美分:
不相信任何人 过滤输入,转义输出(cookie、会话数据也是您的输入) 避免 XSS(保持 HTML 格式正确,查看 PHPTAL 或 HTMLPurifier) Defense in depth 不公开数据关于这个主题有一本小而好的书:Essential PHP Security by Chris Shiflett。
Essential PHP Security http://shiflett.org/images/essential-php-security-small.png
在本书的主页上,您会找到一些有趣的代码示例和示例章节。
您可以使用上述技术(IP 和 UserAgent),在此处描述:How to avoid identity theft
【讨论】:
+1 用于 XSS 预防。没有它,就不可能防止 CSRF,因此有人可以“骑”会话而无需获取会话 ID。【参考方案12】:我是这样设置会话的-
在登录页面上:
$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);
(在配置页面上定义的短语)
然后在整个网站其余部分的标题上:
session_start();
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']))
session_destroy();
header('Location: http://website login page/');
exit();
【讨论】:
【参考方案13】:php.ini
session.cookie_httponly = 1
change session name from default PHPSESSID
eq Apache 添加头文件:
X-XSS-Protection 1
【讨论】:
httpd.conf ->X-XSS-Protection
一点用处都没有。事实上,保护算法本身实际上可以被利用,使其比以前更糟。以上是关于PHP 会话安全的主要内容,如果未能解决你的问题,请参考以下文章