PHP会话安全


125

用PHP维护负责的会话安全性有哪些准则?网络上到处都是信息,现在是时候将所有信息集中在一个地方了!

Answers:


88

为了确保会话安全,需要做几件事:

  1. 对用户进行身份验证或执行敏感操作时,请使用SSL。
  2. 只要安全级别发生更改(例如登录),就重新生成会话ID。如果愿意,您甚至可以为每个请求重新生成会话ID。
  3. 会话超时
  4. 不要使用全局寄存器
  5. 将身份验证详细信息存储在服务器上。也就是说,请勿在Cookie中发送诸如用户名之类的详细信息。
  6. 检查$_SERVER['HTTP_USER_AGENT']。这为会话劫持增加了一个小障碍。您也可以检查IP地址。但是,由于多个Internet连接上的负载平衡等原因,这会给具有更改IP地址的用户带来问题(在我们的环境中就是这种情况)。
  7. 锁定对文件系统上会话的访问或使用自定义会话处理
  8. 对于敏感操作,请考虑要求登录用户再次提供其身份验证详细信息

15
仅对某些操作使用SSL是不够的,除非您有单独的会话来处理加密和未加密的流量。如果您通过HTTPS和HTTP使用单个会话,则攻击者将在第一个非HTTPS请求上窃取它。
Kornel

6
-1用户代理对于欺骗是微不足道的。您所描述的是浪费代码,而不是安全系统。
rook 2010年

24
@The Rook,这可能是一个微不足道的障碍(攻击者可以使用他们自己的站点捕获受害者的用户代理),并且通过隐蔽性依赖于安全性,但这仍然是一个额外的障碍。如果在会话使用期间更改User-Agent HTTP,它将非常可疑,并且很可能是攻击。我从未说过可以单独使用它。如果将其与其他技术结合使用,则您的站点将更加安全。
grom 2010年

5
@grom我觉得它像一个放一块透明胶带在你的门,并说这将阻止人们打破。

8
如果您正在检查用户代理,则当IE8用户切换兼容模式时,您将阻止他们发出的所有请求。在我自己的代码中看到我找到这个问题的乐趣:serverfault.com/questions/200018/http-302-problem-on-ie7。我正在检查用户代理,因为像其他人所说的那样,欺骗是一件微不足道的事情。
bestattendance,2010年


11

我的两分(或更多分):

  • 不信任任何人
  • 过滤输入,转义输出(cookie,会话数据也是您的输入)
  • 避免使用XSS(保持HTML的格式正确,看看PHPTALHTMLPurifier
  • 纵深防御
  • 不公开数据

关于此主题有一本很小但很好的书:Chris Shiflett撰写的Essential PHP Security

基本的PHP安全性http://shiflett.org/images/essential-php-security-small.png

在本书的首页上,您会找到一些有趣的代码示例和示例章节。

您可以使用上述技术(IP和UserAgent),在此进行介绍:如何避免身份盗用


+1以防止XSS。否则,就无法防范CSRF,因此有人可以“乘搭”该会话,而无需获取会话ID。
Kornel

11

我认为主要问题之一(在PHP 6中已解决)是register_globals。现在的用于避免标准方法之一register_globals是使用$_REQUEST$_GET$_POST阵列。

做到这一点的“正确”方法(从5.2版开始,虽然那里有些小虫子,但是从6开始稳定,即将推出)是通过滤镜

所以代替:

$username = $_POST["username"];

你会做:

$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

甚至只是:

$username = filter_input(INPUT_POST, 'username');

2
这根本与问题无关。
Pixel开发人员

5
真?那么,为什么在接受的答案中他们提到不使用寄存器全局变量呢?就大多数常规开发人员而言,即使从技术上讲,它不是“会话”对象的一部分,对全局变量进行注册并形成变量处理也不会属于“会话”的范畴吗?
cmcculloh

9
我同意,这不同 完全回答问题,但这绝对是问题答案的一部分。再次,这在公认的答案中指出了一个要点:“不要使用全局寄存器”。这说明了该怎么做。
cmcculloh


5

根据我的经验,使用IP地址并不是最好的主意。例如; 我的办公室有两个IP地址会根据负载使用,我们在使用IP地址时经常遇到问题。

相反,我选择将会话存储在服务器上域的单独数据库中。这样,文件系统上的任何人都无法访问该会话信息。这对于3.0之前的phpBB确实很有帮助(它们已经修复了此问题),但是我认为这仍然是一个好主意。


3

这是非常琐碎且显而易见的,但是请确保每次使用后都使用session_destroy。如果用户未明确注销,则可能难以实现,因此可以设置计时器来执行此操作。

这是有关setTimer()和clearTimer()的很好的教程


3

PHP会话和安全性的主要问题(会话劫持除外)与您所处的环境有关。默认情况下,PHP将会话数据存储在OS的temp目录中的文件中。无需任何特殊考虑或计划,这是一个世界可读的目录,因此您的所有会话信息对有权访问服务器的任何人都是公开的。

至于在多台服务器上维护会话。到那时,最好将PHP切换到用户处理的会话,在该会话中它将调用您提供的函数以CRUD(创建,读取,更新,删除)会话数据。届时,您可以将会话信息存储在数据库或类似内存缓存的解决方案中,以便所有应用程序服务器都可以访问数据。

如果您在共享服务器上,则存储自己的会话也可能是有利的,因为它将使您将其存储在数据库中,而数据库通常比文件系统具有更多的控制权。


3

我像这样设置会话

在登录页面上:

$_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();     
}

3

php.ini

session.cookie_httponly = 1
change session name from default PHPSESSID

eq Apache添加标头:

X-XSS-Protection    1

httpd.conf-> <FilesMatch“ \。(php | phtml | aspx | htm | html)$”>标头设置了X-XSS-Protection“ 1” </ FilesMatch>
user956584

请注意,这X-XSS-Protection根本没有用。实际上,实际上可以利用保护算法,使其比以前更糟。
Pacerier

2

我将同时检查IP和用户代理,以查看它们是否发生了变化

if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
    || $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
{
    //Something fishy is going on here?
}

5
如果用户位于负载平衡的代理服务器场后面,则IP可以合法更改。
Kornel

2
用户每次升级浏览器时,user_agent都可以更改。
斯科特,

3
@scotts我同意IP部分,但是对于浏览器升级,您将在他们登录时设置会话,因此我看不到他们如何在不再次登录后不创建新会话的情况下升级浏览器。
杰森·戴维斯(JasonDavis)2009年

我相信在IE8中的兼容模式之间切换时,user_agent也可以更改。伪造也很容易。

是的,但是拥有静态IP eq GSM并且每半小时更换一次的用户呢?因此,在会话+主机名中存储IP,当IP!= REMOTE_ADDR检查主机并比较hostanmes eq。12.12.12.holand.nl-> when is holand.nl == true。但是某些主机具有基于IP的主机名,则需要比较掩码88.99.XX.XX
user956584'5

2

如果使用session_set_save_handler(),则可以设置自己的会话处理程序。例如,您可以将会话存储在数据库中。有关数据库会话处理程序的示例,请参考php.net注释。

如果您有多个服务器,则DB会话也很好,否则,如果您正在使用基于文件的会话,则需要确保每个Web服务器都可以访问同一文件系统以读取/写入会话。


2

您需要确保会话数据是安全的。通过查看您的php.ini或使用phpinfo(),您可以找到会话设置。_session.save_path_告诉您它们的保存位置。

检查文件夹及其父文件夹的权限。它不应该是公共(/ tmp)或共享服务器上的其他网站可以访问的。

假设您仍然想使用php会话,则可以通过更改_session.save_path_来将php设置为使用其他文件夹,或者通过更改_session.save_handler_来将数据保存在数据库中。

您可能可以在php.ini(某些提供程序允许)中或在网站根文件夹.htaccess文件中的apache + mod_php中设置_session.save_path_ php_value session.save_path "/home/example.com/html/session"。您还可以在运行时使用_session_save_path()_进行设置。

查看Chris Shiflett的教程Zend_Session_SaveHandler_DbTable来设置和替代会话处理程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.