热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PHP的Session托管机制容易造成漏洞

以下内容针对使用PHP的session_set_save_handler的托管机制进行PHP会话管理托管的开发人员。假定我们通过open,close,pick,dump,clear,gc六个函数对PHP的会话管理进行托管。PHP的session的gc回收机制本身没有问题,问题在于对于未进行gc回收,而又已经

以下内容针对使用PHP的session_set_save_handler的托管机制进行PHP会话管理托管的开发人员。 假定我们通过open, close, pick, dump, clear, gc六个函数对PHP的会话管理进行托管。PHP的session的gc回收机制本身没有问题,问题在于对于未进行gc回收,而又已经

以下内容针对使用PHP的session_set_save_handler的托管机制进行PHP会话管理托管的开发人员。


假定我们通过open, close, pick, dump, clear, gc六个函数对PHP的会话管理进行托管。PHP的session的gc回收机制本身没有问题,问题在于对于未进行gc回收,而又已经过时了的session。


PHP应用中,会话管理都可以依赖于传统的gc机制进行回收,然而当一个项目的并发越高,而gc回收的几率越高,对于数据库(或者IO)而言是一大负荷,所以面对并发高的站点,我们都会将gc回收的基数增加(ini_set('session.gc_pisor', xxxx);),这个也不是本文要讨论的问题重点,所以具体就不讨论了。


当尝试对会话进行托管控制,实际上一方面是为了减轻PHP会话机制本身的一些弊端(减少在$_SESSION变量中存放重要的用户信息),其次,也能帮助我们更好的掌握和管理整个系统的会话。


一个标准的设计,会话数据本身,会为其设计一个生命周期,当超过声明周期的会话,当用户的客户端再持有该session_id而发生会话处理时,则认为该session已经无效,用户当重新登录以维持与服务端的会话连接。

$sessName="MY_APP_SID";
session_name($sessName);
session_start(); // => 此处将立刻调用刚才托管的open和pick两个函数


对于一个open函数:


function open($sessId) {
$sess=/* 根据$sessId获取到会话数据 */;
if ($sess->isValid()) { /* 检查会话是否有效 */
return$anyVal;
}
returnfalse;
}

open函数,就是读取该客户端持有的sessId,并且读取该会话的value值($_SESSION中的值),这中间PHP会内部将$anyVal进行session_decode()返回到$_SESSION中。


当一个会话的isValid返回false的时候,我们会需要重新生成会话id,并且通知客户端更新。PHP为我们提供了这么一个函数:session_regenerate_id(),但是何时使用这个函数,是整个问题的关键。作为服务器与客户端之间的无缝转换,关键的一步在于dump的时候,偷偷的将新生成的sessId写入记录容器(数据库,内存or I/O),然而dump函数,是作为整个PHP运行过程中的末尾部分,header已经输出,你无法重新改写header。或者简单的说,我们日常编写的PHP代码,无论篇幅大小,都是经由open -> dump这个过程中执行的,当会话机制运行到dump过程时,我们已经无可扭转。


解决此问题的落实点在于最初执行session_start的时候,session最初启动的时候,即可执行session_regenerate_id,但是需要一个全局的监控(这时候js的让人十分怀念,可是php无法做到)。


$sessName="MY_APP_SID";
$isRegenerateId=false;
session_name($sessName);
session_start(); // => 此处将立刻调用刚才托管的open和pick两个函数
if ($isRegenerateId)
session_regenerate_id();


而在open的函数中,则是用于通知$isRegenerateId是否变更了:


function open($sessId)
....

if ($sess->isValid()) { /* 检查会话是否有效 */
return$anyVal;
}
else {
$isRegenerateId=true;
}
....


dump如何处理,这里就不再例举了,因为当执行了regenerate以后,全局的session_id都会自动的跟随变化。


不过美中不足的是,PHP的OOP的闭合特性不够强大,$isRegenerateId这么一个重要的变量,暴露在任何环境中都是极度危险的,即便使用private也是十分危险的,越是私有,越容易让代码的状态不可控(这方面让人非常羡慕Scala,一个能同时拥有val和var,你只需要声明sealed类作为一个全局的监视器,就能轻松解决此问题,可惜PHP不行)。于是可以有以下方式进行调整:


$sessName="MY_APP_SID";
session_name($sessName);
session_start(); // => 此处将立刻调用刚才托管的open和pick两个函数
if (defined('REGENERATE_SESS_ID'))
session_regenerate_id();


很自然的,open里面,当isValid为false时,define('REGENERATE_SESS_ID', true)即可。


最后说说,不进行regenerate的后果是什么:


首先,从会话托管的设计初衷而言,让每一个会话本身具有生命周期,就是为了避开沉重的全局回收,让session数据得以冗余而暂时存在,却又不会对该会话持有者造成太大的影响与干扰,如果强行删除会话,客户端必然需要重新登录,这也只是其中的一种情况,如果没有控制好,可能会导致同样的sessId存在多条实例,或者本应超过生命周期的会话重新被激活。当然,也许处在全局的安全性考虑,客户端的个别体验都可以忽略不计,尤其是网站应用方面而言,很少有持续维持会话生命超过十几个小时的。然而这也仅限于网站方面,对于API,或者游戏,对于会话生命周期的要求,就越发的严格。如果站在企业级应用,某些时刻,某些局部,真的是分秒必争。能做到无缝的session生命周期的传承与转换,还是十分重要的。


其次,作为一个系统而言,session往往持有着重大的用户信息,无论怎么完善的系统设计,客户端和服务器之间总需要一条红绳。在特殊应用中,session总是会持有更多特殊的数据,安全的转移,并制造适当的冗余,才能为日后的数据管理,数据回报提供更加完善准确的数据。再者,只有全面的实现设计的全部,才能总结并推演出更加完善的结构,不知道bug的存在,才是最大的风险。

推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 处理docker容器时间和宿主机时间不一致问题的方法
    本文介绍了处理docker容器时间和宿主机时间不一致问题的方法,包括复制主机的localtime到容器、处理报错情况以及重启容器的步骤。通过这些方法,可以解决docker容器时间和宿主机时间不一致的问题。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 本文介绍了Java的集合及其实现类,包括数据结构、抽象类和具体实现类的关系,详细介绍了List接口及其实现类ArrayList的基本操作和特点。文章通过提供相关参考文档和链接,帮助读者更好地理解和使用Java的集合类。 ... [详细]
  • PDF内容编辑的两种小方法,你知道怎么操作吗?
    本文介绍了两种PDF内容编辑的方法:迅捷PDF编辑器和Adobe Acrobat DC。使用迅捷PDF编辑器,用户可以通过选择需要更改的文字内容并设置字体形式、大小和颜色来编辑PDF文件。而使用Adobe Acrobat DC,则可以通过在软件中点击编辑来编辑PDF文件。PDF文件的编辑可以帮助办公人员进行文件内容的修改和定制。 ... [详细]
  • 单点登录原理及实现方案详解
    本文详细介绍了单点登录的原理及实现方案,其中包括共享Session的方式,以及基于Redis的Session共享方案。同时,还分享了作者在应用环境中所遇到的问题和经验,希望对读者有所帮助。 ... [详细]
  • 本文介绍了在Docker容器技术中限制容器对CPU的使用的方法,包括使用-c参数设置容器的内存限额,以及通过设置工作线程数量来充分利用CPU资源。同时,还介绍了容器权重分配的情况,以及如何通过top命令查看容器在CPU资源紧张情况下的使用情况。 ... [详细]
author-avatar
mobiledu2502857983
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有