技术

IT这个行当之需求与时间管理 golang结构体和包中的类型或基础类型定义方法 golang中结构体的初始化方法(new方法) 项目管理总结 python函数式编程之-装饰器(Decorators) python文件批量处理 Go,互联网时代的C Python推导式演变(Comprehensions) 项目管理感悟 golang学习简单例子 了解GitHub工作流【译】 PHP Socket的使用 Apache 日志文件格式及简单处理 Python脚本--下载合并SAE日志 PHP命名空间及自动加载 基于CSS3实现尖角面包屑 部署Ceilometer到已有环境中 OpenStack Ceilometer Collector代码解读 OpenStack Ceilometer数据存储与API源码解析 OpenStack Ceilometer中的Pipeline机制 OpenStack Ceilometer Compute Agent源码解读 学习Python动态扩展包stevedore 学习Python的ABC模块 Python包管理工具setuptools详解 OpenStack Horizon 中文本地化 WSGI学习 在虚拟机单机部署OpenStack Grizzly 学习使用python打包工具distutils python包工具之间的关系 给OpenStack创建Ubuntu镜像 OpenStack Grizzly Multihost部署文档 为什么使用pip而不是easy_install HTML中meta标签viewpoint的作用 交互式编程-IPython 页面提速之——数据缓存 给OpenStack创建Win7镜像 Ceilometer的命令行使用 部署一个ceilometer-horizon项目 给OpenStack创建Windows XP镜像 几种企业的存储系统 概念模型、逻辑模型、物理模型的区别 五中常见的开源协议整理(BSD,Apache,GPL,LGPL,MIT) OpenStack监控项目Ceilometer的一些术语 VNC和远程桌面的区别 OpenStack Ceilometer项目简介 虚拟化与云计算中KVM,Xen,Qemu的区别和联系 调试和修改OpenStack中的Horizon部分 JavaScript变量作用域 kanyun worker原理 kanyun server服务 在OpenStack中部署kanyun kanyun的api-client命令 sae下的python开发部署和一个简单例子 OpenStack Nova内部机制 PHP可变变量 JS中防止浏览器屏蔽window.open PHP操作Session的原理及提升安全性时的一个问题

标签


PHP操作Session的原理及提升安全性时的一个问题

2012年09月19日

Session和Cookie基本介绍

相同点:两者都是保存用户的临时信息,以方便用户和网站之间的交互

不同点:Session保存在服务器端,只有服务器端才可查看和修改。服务器端通过客户端在cookie中携带的session_id来获得保存在服务器端的用户数据。Cookie保存在客户端,服务端和客户端都可以对其进行修改。

Session的工作原理

首先测试如下一段代码

<?php
session_start();//开启session
echo ‘Session id:’.session_id().‘<br>’;//显示此次交互的session_id
?>

页面显示结果为

Session id:ihrk96384qjvvsqmce0dlkla04

即使不停刷新页面,依然不变,说明服务器端是可以识别出客户端,那么它是如何做到的呢?

我们可以查看一下他们的第一次HTTP交互(先清空一次cookie和缓存再测试)

Request Header:
GET /phptest/test2.php HTTP/1.1
Host: localhost
Cookie:
Response Header:
Set-Cookie: PHPSESSID=sastrf9cikeij6meoe3055brq3; path=/

为了说明问题,我只取要用到的信息,从请求头可以看到,这个时候客户端没有给服务端传Cookie内容。而返回的头信息中,服务端指明了set-cookie要设置一个PHPSESSID的内容,保存在”/”目录下。

来看第二次交互:

Request Header:
GET /phptest/test2.php HTTP/1.1
Host: localhost
Cookie:PHPSESSID=sastrf9cikeij6meoe3055brq3
Response Header:
Set-Cookie:

这一次结果显示服务器端没有再要求写Cookie,而客户端主动上传了上次获得的PHPSESSID值,也就是这种机制,使服务端”认识”了客户端。只要服务端没有要求再次写session,则以后的交互将一直以此session_id作为客户端的身份标志。

服务器端修改Session_id

当然sessionid不是永久不变的,当我们清空过一次Cookie以后就发现以前登录了的网站都得重新登陆。再次登陆的时候,我们又会以新的sessionid来进行重新确认身份。(注:还有别的方式可以传递session_id值,例如query string等)。

其实从上一个例子中我们就可以看到,服务器端修改session_id其实是通过重写一次cookie来实现的,这次重写发生在一次请求完成以后,即传回的HTTP头中说明的。

为了防止Session劫持,我们可能需要通过每次请求都更改session_id来确保用户是本人登录的。在php中,可以使用以下方式:

<?php
session_start();//开启session
        echo ‘Old Session id:’.session_id().‘<br>’;
session_regenerate_id(true);//重置session_id,并使原session无效
        echo ‘New Session id:’.session_id().‘<br>’;
    ?>

页面显示结果为:

Old Session id:mqk5sfudpu9ikgp49vc825ggo6
New Session id:mrck9n85v190reupsni4ob6lo5

可见sessionid在使用了sessionregenerate_id()以后发生了变化,变化写入方式同第二点介绍的,服务器端在返回的HTTP头中加入Set-Cookie。

sessionregenerateid()的一个问题

在实际操作中,session_id的保存位置可以通过

session_set_cookie_params()

来修改,如下:

<?php
session_set_cookie_params(0,‘/’,‘testdomain’);
session_start();//开启session
        echo ‘Old Session id:’.session_id().‘<br>’;
session_regenerate_id(true);//重置session_id,并使原session无效
        echo ‘New Session id:’.session_id().‘<br>’;
?>

在这种方式下,sessionid的默认domain被修改,但是sessionregenerate_id()是不识别的。这不知道算不算php的一个bug,为了解决这个问题,我们必须使用手动方式重置session保存,修改代码如下:

<?php
session_set_cookie_params(0,‘/’,‘testdomain’);
session_start();//开启session
        echo ‘Old Session id:’.session_id().‘<br>’;
session_regenerate_id(true);//重置session_id,并使原session无效
        echo ‘New Session id:’.session_id().‘<br>’;
setcookie(session_name(),session_id(),0,‘/’,‘testdomain’);//手动更新session_id
?>

这样一来就可以每次交互更新session_id了……虽然有些复杂,但是经测试可行。