中文

杂谈 os包的功能 Amaze UI中的组件 Skeleton CSS的用武之地 SVG Introduction mysql数据库迁移 How agent and message bus work in the CloudStack platform? 剖析cloudstack中虚机的创建过程 AngularJS与LoopBack LoopBack实战 Sails使用手册 在NodeJS中使用MySQL数据库 在NodeJS中使用Sqlite 实战XLRD类库 上下文中给模板中的变量赋值 使用Pecan创建restful API 服务 使用python语言操作excel文件 Magento性能调优 Celery的世界 Linux下如何快速查找文件和内容 MySQL常用资源 为PHP设置服务器(Apache/Nginx)环境变量 MySQL大量数据插入各种方法性能分析与比较 Laravel中使用Redis作为队列系统的工作流程 使用Supervisor来管理你的Laravel队列 在Laravel中使用自己的类库三种方式 用Xdebug和Sublime调试PHP代码 用Laravel+Grunt+Bower管理你的应用 PHP Socket的使用 Python脚本--下载合并SAE日志 PHP命名空间及自动加载 SVN 常用资源 Shell 常用资源 Python 常用资源 PHP 常用资源 jQuery 常用资源 JavaScript 常用资源 HTML 常用资源 Git 常用资源 Linux下多个命令连续执行方法 基于CSS3实现尖角面包屑 部署Ceilometer到已有环境中 更新前端框架到Bootstrap3 OpenStack Ceilometer数据存储与API源码解析 OpenStack Ceilometer中的Pipeline机制 OpenStack Ceilometer Compute Agent源码解读 学习Python动态扩展包stevedore 学习Python的ABC模块 Python包管理工具setuptools详解 OpenStack Horizon 中文本地化 安装MySQL和MongoDB的WEB管理界面 给Git或者APT设置goagent代理 WSGI学习 在虚拟机单机部署OpenStack Grizzly python包工具之间的关系 给OpenStack创建Ubuntu镜像 OpenStack Grizzly Multihost部署文档 HTML中meta标签viewpoint的作用 交互式编程-IPython 页面提速之——数据缓存 给OpenStack创建Win7镜像 Ceilometer的命令行使用 给OpenStack创建Windows XP镜像 概念模型、逻辑模型、物理模型的区别 Bootstrap常用资源 OpenStack监控项目Ceilometer的一些术语 服务器自动化部署及运维常见工具 Linux下开启Libvirtd的tcp监控 VNC和远程桌面的区别 调试和修改OpenStack中的Horizon部分 win7快速打开应用程序或文件 JavaScript变量作用域 git创建远程库 MySQL远程访问 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

当然session_id不是永久不变的,当我们清空过一次Cookie以后就发现以前登录了的网站都得重新登陆。再次登陆的时候,我们又会以新的session_id来进行重新确认身份。(注:还有别的方式可以传递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

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

session_regenerate_id()的一个问题

在实际操作中,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>’;
?>

在这种方式下,session_id的默认domain被修改,但是session_regenerate_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了……虽然有些复杂,但是经测试可行。