zoukankan      html  css  js  c++  java
  • 正确理解 Session 的安全性

    Session 是 Web 开发中必须涉及的一个话题,面试的时候很多人理解 Session 和 Cookie 的时候总是就一句“一个存储在服务器端,一个存储客户端”,被面试的人回答的时候可能自己也觉得很空洞,而面试官肯定也会很不满意,其实完全可以换个话题来考察对于 Session 的理解,这就是这篇博文的题目“正确理解 Session 的安全性”。

    在 PHP 语言中,Session 安全性这个锅不能全部让 PHP 背。Session 不安全的根本原因其实就是二点,第一个就是会话传递机制导致的(Cookie 和 URL参数)劫持问题(只要有网络就会有劫持,所以劫持不是这篇博文的重点),另外个就是会话固定的问题。

    假如你仅仅使用 PHP 原生的函数去管理你的 Session,可能会有安全性的问题,所以提倡使用第三方的 Session 类库(它考虑很多安全性问题)。
    另外 PHP 本身也提供了很多指令和方法来提高安全性(很多文章描述 Session 有多么不安全,并且弄出了很多解决方案,但其实高版本的 PHP 提供了很多内置的解决方案,这就是看手册的重要性)。

    简单描述下 Session ,Session 的数据是存储在服务器端的,那么服务器如何保持会话呢(或者说如何找到特定的用户呢?),可以通过二种方式(Cookie 和 URL 参数)来传递。一涉及到传递就比如会有危险,并且在 PHP 中这个危险被放大了。

    Session ID 可以使用 Cookie 和 URL 参数来传递,相对来说,Cookie 更安全( URL 暴露的频率更高),假如你不考虑 Cookie 被禁用的问题,你应该只使用 Cookie 来传递。PHP.ini 提供了 session.use_only_cookies 指令来加强安全性。

    Cookie 本身也是不安全的,所以提升 Cookie 安全性的方法也同样适用与 Session。
    关键的就是 HttpOnly(不允许 Javascript 脚本读取),另外假如你的网站是支持 Https 协议的,那么配置 Cookie 只能通过 Https 协议传递。

    很多开发者非常注意 Session 的 GC 过期时间,GC 代表到了特定日期,PHP 会自动清除服务器端的 Session 文件,但是还很多人理解这个概念有误区:

    Session 的存活时间是“变化的”,只要会话一初始化,Session 文件的修改时间就会更新,换句话说,设置该 GC 时间为 2 小时过期,但是只要用户间隔 2 小时一直保持会话更新(比如刷新页面),则 Session 一直会存在。
    GC 到期后,由 PHP 来控制删除 Session 文件,但是并不是每次就会删除过期文件,所以不能依赖它(但是可以通过自定义 Session 管理器来实现这个机制)。
    考虑到 Session GC 不可依赖,所以间接的可以设置 Cookie 对应的过期时间(session.cookie_lifetime 指令)等于 GC 时间,这样一到过期时间,由于 Cookie 失效了,等同于 Session 也失效了(虽然 Session 对应的文件并没有删除,假如攻击者知道 Session ID 还是会带来安全问题)。

    Session Time-Outs

    由于 Session 的 GC 不能依赖,所以很多类库通过一些方案来解决该问题,考虑这样一个场景“假如你登陆了一个网站,并且很长时间没有操作了”,那么这个会话有效吗?理论上来说应该不算有效,会话的有效时间应该是“变化的”,当用户触发了会话,则更新一次(等于将过期时间延长)。

    session_start();
    $activeTime = 3600;
    $t = time();
    $lastactivetime = $_SESSION["lastactivetime"] ;
    if (isset($lastactivetime)) {
        if (($lastactivetime + $activeTime) > $t) {
            return;
        }
    }
    $_SESSION["lastactivetime"] = $t;
    

    在 PHP CodeIgniter 框架中,这个激活有效时间称为 sess_time_to_update。
    当然这个方法也并不是特别安全,因为一般来说攻击者会不断的维持会话处于“激活状态”。

    Regenerate the Session ID

    假如攻击者劫持了你的 Session ID,但是你又不知道,为了安全建议经常性的重置 Session ID(比如不定期的使用session_regenerate_id()函数),这样攻击者等同于拿到的是旧的 Session ID(假设新的 Session ID 攻击者获取不到),这样就不能获取 Session 数据了。
    但这也不是完全有效的(因为攻击者有方法能劫持你的 Session ID)。

    更有效的方式其实应该是在用户操作更高权限功能的时候(比如电商结账的时候),让用户重新输入密码去验证(获取用户密码是另外一种攻击方式 )。这是从应用层角度考虑最有效的保护方式。

    会话固定

    会话固定我理解为二层意思,只要有正确的 Session ID ,不管你从什么设备上发起请求,服务器程序校验出有对应的 Session 信息就认为是正确的,第二层意思就是假如客户端伪造一个 Session ID(伪造包含二部分,第一本身服务器上没有这个 Session ID,第二 Session ID的值格式也可以是错误的),PHP 处理的时候看到这个 Session ID不存在,就以这个Session ID 去初始化,这样的机制可能带来攻击。

    举个例子,一个攻击者发送你一个连接,比如 https://www.jd.com/?SID=1234,你打开后,看到的是京东的网站,然后你登录了(这时候有了正确的身份验证信息),攻击者这时候在自己的电脑就能以你的身份购买东西了(因为攻击者和用户是同一个 Session ID)。

    那么如何解决呢?除了上面提到的一系列方法,还可以提供二个方法。

    第一种是应用层的解决方案,上面说了 Session ID 和客户端环境没有关系,那么可以加上这个关系,比如初始化 Session ID 的时候,可以将用户浏览器的 UA 头保存到 Session 信息中,假如攻击者想通过这个 Session ID 获取权限的时候,服务器端代码一看这个 Session ID 中的 UA 信息和访问者不一样,就认为是非法请求。

    第二种解决方案是 PHP 提供的,session.use_strict_mode 指令假如开启,未初始化的 Session ID PHP 会重新生成一个,很大程度上解决了安全问题。

    在这个指令没出现的情况下,一般通过如下方式去解决:

    //使用 session_id 作为校验 ID
    session_destory();
    session_regenerate_id();
    $_SESSION['valid_id'] = session_id(); 
    
    //校验 session_id 是否初始化
    if ($_SESSION['valid_id'] !== session_id()) {
      session_regenerate_id();
      $_SESSION['valid_id'] = session_id(); 
    } 
    

    最后,安全问题是相对的,没有绝对的安全,尽量让其更安全,并通过应用解决方案去提升安全。

    并且这里也没有提到如何进行 Session 劫持的问题,这已经不属于 PHP 解决的范畴了。

    正确的关闭会话方式

    很多开发者在用户退出的时候,不会主动或者正确的关闭会话,关闭会话包含三个方面,第一就是传递 Session ID 的 Cookie 应该删除,第二就是 Session 文件应该删除,第三在 PHP 进程中的 Session 全局变量也应该清除,用代码来说明下:

    $_SESSION = array();
    session_unset();
    $name = session_name();
    if (isset($_COOKIE[$name])) {
        $r = session_get_cookie_params();
        setcookie($name, '', time() - 3600, $r['path'], $r['domain'], $r['
        secure'], $r['httponly']);
    }
    session_destroy();
    
  • 相关阅读:
    MFC添加图标到托盘
    MFC中CString转int,double
    c语言练习13——打印出所有的“水仙花数”
    c语言练习12——判断101-200 之间有多少个素数,并输出所有素数
    c语言练习11——兔子问题
    c语言练习10——输出国际象棋棋盘
    c语言练习9——打印楼梯和笑脸
    c语言练习8——输出9*9 乘法表
    c语言练习7——输出特殊图案
    c语言练习6——用*号输出字母C的图案
  • 原文地址:https://www.cnblogs.com/echojson/p/12804752.html
Copyright © 2011-2022 走看看