PHP会话安全

PHP会话安全

PHP Session Security

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


为了确保会话安全,需要执行以下几项操作:

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

  • 一种准则是,每次会话的安全级别更改时,都要调用session_regenerate_id。这有助于防止会话劫持。


    我的两分(或更多分):

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

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

    基本的PHP安全性/d/jc/2023041113/qpf3q0bdjpq05.webp

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

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


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

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

    所以代替:

    1
    $username = $_POST["username"];

    你会做:

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

    甚至只是:

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

    此会议注视文件提供了很好的指示,指出了攻击可能发生的地方。另请参阅Wikipedia上的会话固定页面。


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

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


    php.ini

    1
    2
    session.cookie_httponly = 1
    change session name from default PHPSESSID

    eq Apache添加标头:

    1
    X-XSS-Protection    1

    我像这样设置会话

    在登录页面上:

    1
    $_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);

    (短语在配置页面上定义)

    然后在网站其余部分的标题上:

    1
    2
    3
    4
    5
    6
    session_start();
    if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR'])) {      
        session_destroy();
        header('Location: http://website login page/');
        exit();    
    }

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

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

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


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

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


    您需要确保会话数据是安全的。通过查看您的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来设置和替代会话处理程序。


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

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


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

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


    推荐阅读