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

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

以下内容针对使用PHP的session_set_save_handler的托管机制进行PHP会话管理托管的开发人员。
以下内容针对使用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_divisor',xxxx);),这个也不是本文要讨论的问题重点,所以具体就不讨论了。

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

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

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

  对于一个open函数:

								
    1. function open($sessId) {     
    2.     $sess = /* 根据$sessId获取到会话数据 */;     
    3.     if ($sess->isValid()) { /* 检查会话是否有效 */    
    4.         return $anyVal;     
    5.     }     
    6.     return false;     
    7. }   

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

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

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

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

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

																															
    1. function open($sessId) {     
    2.     ....     
    3.          
    4.     if ($sess->isValid()) { /* 检查会话是否有效 */    
    5.         return $anyVal;     
    6.     }     
    7.     else {     
    8.         $isRegenerateId = true;     
    9.     }     
    10.     ....     
    11. }   

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

  不过美中不足的是,PHP的OOP的闭合特性不够强大,$isRegenerateId这么一个重要的变量,暴露在任何环境中都是极度危险的,即便使用private也是十分危险的,越是私有,越容易让代码的状态不可控。于是可以有以下方式进行调整:

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

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

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

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

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

原文链接:http://my.oschina.net/janpoem/blog/6932


推荐阅读
  • 随着Linux操作系统的广泛使用,确保用户账户及系统安全变得尤为重要。用户密码的复杂性直接关系到系统的整体安全性。本文将详细介绍如何在CentOS服务器上自定义密码规则,以增强系统的安全性。 ... [详细]
  • 本文详细介绍如何安装和配置DedeCMS的移动端站点,包括新版本安装、老版本升级、模板适配以及必要的代码修改,以确保移动站点的正常运行。 ... [详细]
  • JavaScript 跨域解决方案详解
    本文详细介绍了JavaScript在不同域之间进行数据传输或通信的技术,包括使用JSONP、修改document.domain、利用window.name以及HTML5的postMessage方法等跨域解决方案。 ... [详细]
  • 搭建个人博客:WordPress安装详解
    计划建立个人博客来分享生活与工作的见解和经验,选择WordPress是因为它专为博客设计,功能强大且易于使用。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • 2017年软件开发领域的七大变革
    随着技术的不断进步,2017年对软件开发人员而言将充满挑战与机遇。本文探讨了开发人员需要适应的七个关键变化,包括人工智能、聊天机器人、容器技术、应用程序版本控制、云测试环境、大众开发者崛起以及系统管理的云迁移。 ... [详细]
  • 本文详细探讨了 Android Service 组件中 onStartCommand 方法的四种不同返回值及其应用场景。Service 可以在后台执行长时间的操作,无需提供用户界面,支持通过启动和绑定两种方式创建。 ... [详细]
  • Windows环境下Oracle数据库迁移实践
    本文详细记录了一次在Windows操作系统下将Oracle数据库的控制文件、数据文件及在线日志文件迁移至外部存储的过程,旨在为后续的集群环境部署做好准备。 ... [详细]
  • 如何高效学习鸿蒙操作系统:开发者指南
    本文探讨了开发者如何更有效地学习鸿蒙操作系统,提供了来自行业专家的建议,包括系统化学习方法、职业规划建议以及具体的开发技巧。 ... [详细]
  • 本文探讨了使用Python实现监控信息收集的方法,涵盖从基础的日志记录到复杂的系统运维解决方案,旨在帮助开发者和运维人员提升工作效率。 ... [详细]
  • Java虚拟机及其发展历程
    Java虚拟机(JVM)是每个Java开发者日常工作中不可或缺的一部分,但其背后的运作机制却往往显得神秘莫测。本文将探讨Java及其虚拟机的发展历程,帮助读者深入了解这一关键技术。 ... [详细]
  • 服务器虚拟化存储设计,完美规划储存与资源,部署高性能虚拟化桌面
    规划部署虚拟桌面环境前,必须先估算目前所使用实体桌面环境的工作负载与IOPS性能,并慎选储存设备。唯有谨慎估算贴近实际的IOPS性能,才能 ... [详细]
  • 从理想主义者的内心深处萌发的技术信仰,推动了云原生技术在全球范围内的快速发展。本文将带你深入了解阿里巴巴在开源领域的贡献与成就。 ... [详细]
  • 本文详细介绍如何在华为鲲鹏平台上构建和使用适配ARM架构的Redis Docker镜像,解决常见错误并提供优化建议。 ... [详细]
author-avatar
小帅哥沈阳后援会果果
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有