简介


本文的目的是介绍给PHP的Session设置超时的原因,以及其工作原理。我将叙述两种通用的方法来控制一个Session的生命期,并演示如何在你的代码里使用。



问题


PHP的Session机制允许我们服务器上保存客户端数据,并在多重请求里保持。然而,由于数据本身是保存在服务器上,客户端与服务器连接,以获取各自会话的唯一办法是简单的Cookie,这遗留了一个重大的安全问题。


会话劫持(session hijacking),是当一个恶意的第三方从客户端拦截或偷取该Session Cookie,并使用它从一个激活的Session里来访问数据。服务器几乎无法防卫,因为没有途径告知服务器,客户端源自劫持者。



解决方案


足间舞ROOM


最重要的防范措施是,在规定的时间后忽略Session,让其成为非激活的。这样就可以阻止攻击者了,除非他们正在访问的Session的设定的时间内进行攻击。


在PHP里,它的实现机制被视为Session垃圾回收(Garbage Collection)。数据文件通过“最后修改”来附加时间戳,PHP用来确定客户端最后使用Session的时间。如果该Session比一个会话允许的生命期更旧,那它将被销毁。PHP里Session的默认生命期是1440秒或24分钟。


有两种方法可以让我们手动配置Session的生命期:



方法一:手动编码


你可以简单地添加一个代码片断到你站点的每个页面的顶部,将当前时间设定到Session的一个字段里。然后通过该字段,可以确定多久之后让该Session失效。举例:



session_start();
$timeout = 60;
if(isset($_SESSION['timeout'])){
$duration = time() - (int)$_SESSION['timeout'];
if($duration > $timeout){
session_destory();
session_start();
}
}

足间舞ROOM


$_SESSION['timeout'] = time();


方法二:重新设定PHP的Session垃圾回收


PHP.ini的session.gc_maxlifetime指令控制了一个Session在它被识为垃圾并被清理前,允许存在的时间长度。每次调用session_start()函数都有机会触发垃圾回收程序。


这个“有机会触发”是由session.gc_probabilitysession.gc_divisor指令决定的。该机率通过下式计算:

session.gc_probability / session.gc_divisor


默认值是1和100交替,或1%可能垃圾回收被触发。如果你的网站流量很小,你可以增加session.gc_probability的值来增加机率。如果你想保证它会触发,可以将两个指定设置为相同的值。


另一个需要考虑的是,PHP将Session数据存储在哪个目录里。PHP将在相同的目录里的所有的Session数据文件应用相同的生命期;把最小的生命期设定给它们。意思是,如果你想确保你的Session正确超时,你需要使用你自己的目录。处理这个问题的最好办法是在你的主目录和临时目录中选择一个,然后创建一个Session数据的存储目录。你可以使用PHP的mkdir()来创建目录,同时通过session.save_path指定来设置路径。


这些值可以使用ini_set函数来设置,因此你可以在Session启动前设置Session垃圾回收的值。例如,这个函数可以用来启动一个Session,同时可以用来获取超时时间的值:



function session_start_timeout($timeout=5, $probability=100, $cookie_domain='/') {
ini_set("session.gc_maxlifetime", $timeout);
ini_set("session.cookie_lifetime", $timeout);

足间舞ROOM


$seperator = strstr(strtoupper(substr(PHP_OS, 0, 3)), "WIN") ? "\\" : "/";
$path = ini_get("session.save_path") . $seperator . "session_" . $timeout . "sec";
if(!file_exists($path)) {
if(!mkdir($path, 600)) {
trigger_error("Failed to create session save path directory '$path'. Check permissions.", E_USER_ERROR);
}
}
ini_set("session.save_path", $path);
ini_set("session.gc_probability", $probability);
ini_set("session.gc_divisor", 100);

session_start();
if(isset($_COOKIE[session_name()])) {
setcookie(session_name(), $_COOKIE[session_name()], time() + $timeout, $cookie_domain);
}
}

要将一个Session的超时时间设置为1分钟,你可以这样调用上面的函数:


足间舞ROOM


session_start_timeout(60);

默认的,它设置100%的机率来触发垃圾回收程序。在一个大流量的站点,这对服务器是一个严峻的考验。你可以传递一个你想要的百分比数给第一个参数,这样便可解决此问题:


session_start_timeout(60, 10);

这样的话,会给10%的机率触发垃圾回收程序。



上一篇 下一篇