PHP中的session安全吗?


Posted in PHP onJanuary 22, 2016

做PHP开发这么长时间,还真没有真正关注过安全的问题,每次都是以完成项目为主,最近在网上看到了一篇关于安全的文章,看完以后才注意到自己以前的项目都存在着很大的安全漏洞,于是挑了一个项目进行了测试,发现很容易就中招儿了。在这里我会分享自己写的一个测试的例子来说明PHP中的session是如何不安全的,以及在项目中如何加强其安全性。
对于session的原理机制,网上有很多好的文章来介绍,我们可以自行查阅。下面直接分享测试用的例子。
这个测试的例子主要就是一个登录页,登录成功以后可以修改密码,就这样一个简单的功能。
界面如下

PHP中的session安全吗?

首先是在项目入口的地方使用函数 session_start() 开启了session。这样当客户端发起请求的时候,会产生一个身份标识 也就是 SessionID。通过cookie的方式保存在客户端,客户端和服务端每次的通信都是靠这个SessionID来进行身份识别的。
登录成功以后,会将 用户id、用户名存入session中

$_SESSION[‘userid'] = 用户id
$_SESSION[‘uname'] = 用户名

以后所有的操作都是通过判断 $_SESSION[‘userid']是否存在来检查用户是否登录。代码如下:

if(isset($_SESSION['userid'])) return true;

对于修改密码接口的调用是通过ajax  post的方式将数据传输到服务端的。

$.post("接口*******",
  {
     oldpass:oldpass,
     newpass:newpass,
     userid:uid,
  },
  function(data){
     data = eval('(' +data+ ')');
     $('.grant_info').html(infos[data.info]).show();
  }
);

注意,我这里将这段代码写在了html页面中,所以说如果看到了html代码,也就知道了接口地址了。
修改密码的接口是这样实现的,首先是判断用户是否登录,如果登录才会进行密码的修改操作。
测试例子的实现思路大概就是上面介绍的那样。
利用SessionID攻击
1. 首先是获取SessionID,当然攻击者获取此标识的方式有很多,由于我的水平有限,至于如何获取我在这里不做介绍。我们可以模拟一下,先正常访问此项目,然后通过浏览器查看SessionID,以此得到一个合法的用户标识。可以在请求头中看到此项ID

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Connection: keep-alive
Cookie: Hm_lvt_bf1154ec41057869fceed66e9b3af5e7=1450428827,1450678226,1450851291,1450851486; PHPSESSID=2eiq9hcpu3ksri4r587ckt9jt7;
Host: ******
Referer: ******
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:41.0) Gecko/20100101 Firefox/41.0

得到sessionID以后,如果此用户登录成功,那么服务端的session里就有此用户的信息了。
2. 获取到SessionID以后,假如攻击者已经知道修改密码的接口,就可以直接修改此用户的密码了。如果攻击者还没有得到接口地址,可以通过查看页面代码找出接口地址。可以使用如下的命令

#curl --cookie "PHPSESSID=2eiq9hcpu3ksri4r587ckt9jt7" 页面地址

上面我们说过,在此例子中ajax代码是写在html页面中的,所以在此页面可以查看到接口地址
部分html代码如下

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
……
var uid = $(".userid").val();
$.post("/User/User/modifypass_do",
     {
        oldpass:oldpass,
        newpass:newpass,
        userid:uid,
     },
    function(data){
      data = eval('(' +data+ ')');
      $('.grant_info').html(infos[data.info]).show();
    }
 );
……
<span><input type="password" name="oldpass" id="textfield_o" placeholder="原密码"></span>
<span><input type="password" name="newpass" id="textfield_n" placeholder="新密码"></span>
<span><input type="password" name="confirmpass" id="textfield_c" placeholder="确认密码"></span>
<input type="button" class="btn_ok" value="确认修改" />

3. 得到接口以后可以通过curl 模拟post发送数据来修改密码
命令如下

# curl --cookie "PHPSESSID=2eiq9hcpu3ksri4r587ckt9jt7" -d oldpass=111111 -d newpass=000000 -d userid=用户id 接口地址

如果此用户已经登录,那么攻击者可以通过执行以上命令修改用户的密码。
解决方法
对于以上方式的攻击,我们可以通过使验证方式复杂化来加强其安全性。其中一种方式就是利用请求头中的User-Agent项来加强其安全性

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Connection: keep-alive
Cookie: Hm_lvt_bf1154ec41057869fceed66e9b3af5e7=1450428827,1450678226,1450851291,1450851486; PHPSESSID=2eiq9hcpu3ksri4r587ckt9jt7;
Host: ******
Referer: ******
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:41.0) Gecko/20100101 Firefox/41.0

在项目开始的时候最初我们只是用了session_start()函数来开启session。现在我们可以在session_start() 下面 添加这段代码

$_SESSION[‘User_Agent'] = md5($_SERVER[‘HTTP_USER_AGENT']);

然后在每次判断是否登录的时候,添加判断条件如下

If(isset($_SESSION[‘userid']) && $_SESSION[‘User_Agent'] == md5($_SERVER[‘HTTP_USER_AGENT'])){
    return true;
}

这样就可以避免上述简单的攻击。
总结:
当然,实际情况中的攻击远非这么简单,首先在获取SessionID这一步就比较困难,然后就是和服务端交互的代码尽量加密,可以避免上述的情况。在我们第二次修改代码以后,可以增加攻击的复杂程度,并不能杜绝攻击。攻击的方式多种多样,这里只是一种简单的方式,仅提供一种思路,但是原理是一样的,在实际情况中可以根据实际情况增强我们代码的安全程度。

这里只是分享自己在工作中碰到的问题,权当抛砖引玉,希望大家可以进一步深入学习。

PHP 相关文章推荐
一个域名查询的程序
Oct 09 PHP
Apache, PHP在Windows 9x/NT下的安装与配置 (一)
Oct 09 PHP
php采集时被封ip的解决方法
Aug 29 PHP
php连接mssql数据库的几种方法
Feb 21 PHP
PHP5函数小全(分享)
Jun 06 PHP
PHP中使用imagick生成PSD文件缩略图教程
Jan 26 PHP
PHP YII框架开发小技巧之模型(models)中rules自定义验证规则
Nov 16 PHP
服务器迁移php版本不同可能诱发的问题
Dec 22 PHP
PHP全局变量与超级全局变量区别分析
Apr 01 PHP
php实现基于openssl的加密解密方法
Sep 30 PHP
php提交表单时保留多个空格及换行的文本样式的方法
Jun 20 PHP
PHP缓存工具XCache安装与使用方法详解
Apr 09 PHP
PHP下载远程图片并保存到本地方法总结
Jan 22 #PHP
PHP连接MYSQL数据库实例代码
Jan 20 #PHP
CodeIgniter配置之autoload.php自动加载用法分析
Jan 20 #PHP
Twig模板引擎用法入门教程
Jan 20 #PHP
CodeIgniter控制器之业务逻辑实例分析
Jan 20 #PHP
CodeIgniter自定义控制器MY_Controller用法分析
Jan 20 #PHP
CodeIgniter钩子用法实例详解
Jan 20 #PHP
You might like
一个ubbcode的函数,速度很快.
2006/10/09 PHP
php打造属于自己的MVC框架
2012/03/07 PHP
使用php检测用户当前使用的浏览器是否为IE浏览器
2013/12/03 PHP
详解PHP安装mysql.so扩展的方法
2016/12/31 PHP
php中str_pad()函数用法分析
2017/03/28 PHP
基于Laravel5.4实现多字段登录功能方法示例
2017/08/11 PHP
php微信公众号开发之关键词回复
2018/10/20 PHP
PHP使用CURL实现下载文件功能示例
2019/06/03 PHP
php实现微信和支付宝支付的示例代码
2020/08/11 PHP
javascript Array数组对象的扩展函数代码
2010/05/22 Javascript
node.js中的buffer.write方法使用说明
2014/12/10 Javascript
Javascript添加监听与删除监听用法详解
2014/12/19 Javascript
AngularJS 与百度地图的结合实例
2016/10/20 Javascript
常用JS图片滚动(无缝、平滑、上下左右滚动)代码大全(推荐)
2016/12/20 Javascript
Vue组件tree实现树形菜单
2017/04/13 Javascript
vue-cli3.0+element-ui上传组件el-upload的使用
2018/12/03 Javascript
解决ie11 SCRIPT5011:不能执行已释放Script的代码问题
2019/05/05 Javascript
Jquery高级应用Deferred对象原理及使用实例
2020/05/28 jQuery
[44:01]2018DOTA2亚洲邀请赛3月30日 小组赛B组 EG VS paiN
2018/03/31 DOTA
Python挑选文件夹里宽大于300图片的方法
2015/03/05 Python
Python中实现结构相似的函数调用方法
2015/03/10 Python
Python爬虫利用cookie实现模拟登陆实例详解
2017/01/12 Python
python实现简单神经网络算法
2018/03/10 Python
Python设计模式之迭代器模式原理与用法实例分析
2019/01/10 Python
使用Python做定时任务及时了解互联网动态
2019/05/15 Python
Python列表list常用内建函数实例小结
2019/10/22 Python
使用Python实现微信拍一拍功能的思路代码
2020/07/09 Python
python绘图pyecharts+pandas的使用详解
2020/12/13 Python
英国现代、当代和设计师家具店:Furntastic
2020/07/18 全球购物
业务经理的岗位职责
2013/11/16 职场文书
运动会100米解说词
2014/01/23 职场文书
2015年植树节活动总结
2015/02/06 职场文书
求职推荐信范文
2015/03/27 职场文书
Redis 常见使用场景
2021/08/30 Redis
vue实现列表拖拽排序的示例代码
2022/04/08 Vue.js
详细介绍Java中的CyclicBarrier
2022/04/13 Java/Android