标题:【PHP小课堂】深入学习PHP中的SESSION(二)

文章目录
    分类:PHP 标签:PHP

    深入学习PHP中的SESSION(二)

    今天的学习内容没有太多的代码,主要还是以理论经验为主,当然,主要的依据还是来源于 PHP 官方文档中的说明。在日常的业务开发中,SESSION 安全一直是我们最主要也是最关心的内容,不管是面向前端的用户还是面向后台的管理员,SESSION 泄露可能都会带来严重的问题。这是我们需要重点的考虑的内容之一。

    会话安全

    从上篇文章中我们了解到,其实 SESSION 之所以能够实现,最核心的内容就是那个 phpsessid ,也就是 session id 。这个就相当于是一个密钥,有了它,我们就可以随便登录我们的系统了。不少小伙伴一下就明白了,要么从 url 中获取,要么从 Cookie 中获取,这个 session id 总共也就这两种传递的形式。


    没错,所以在正常情况下一般都不推荐使用 url 形式来传递这个 session id ,毕竟明文地在连接中简直是太方便获取到了。而 Cookie 的话,比较建议的是设置 Cookie 的 secure 和 http_only 这两个选项。 secure 的作用是让 Cookie 只能通过 https 来进行传输,而 http_only 则是让 Cookie 无法通过 JavaScript 读取,也就是 document.cookie 无法读取 Cookie 。为什么要有这两个操作呢?


    HTTPS 在传输过程中是安全的,也就是说,在传输的过程中,数据是加密的,双方的证书都存在且匹配的情况下它们才会正确地编解码。这就避免了在数据传输过程中的窃取问题的发生。而不让 JavaScript 读取则是应对 XSS 攻击的有效方式,不管是存储型、反射型的 XSS ,核心特点都是在注入成功之后通过窃取 Cookie 来拿到当前帐号的登录权限。通过限制 JS 读取之后,也就无法拿到 Cookie 里面的内容,自然也不会泄露 session id 了。


    除此之外,域信息、路径信息这些 Cookie 中的设置属性也最好都考虑应用上,对于跨域跨站的攻击都是有帮助的。

    重新生成 session id

    除了 Cookie 相关的设置外,每次请求或者说间隔一段时间就重新生成一个 session id 也是一种不错的安全保障机制。也就是说,利用我们上篇文章中学习到的 session_create_id() 或 session_regenerate_id() 这两个函数,在每次请求之后都调用一下,这样都会重新生成一个新的会话ID。就算其他人拿到了之前的 session id ,放到新的请求中也会失效。不过这个操作会有一定的垃圾成本,也就是会产生很多空的 session 文件或者数据。在上篇文章的演示中我们也看到过,重新生成 session id 之后,原来的文件或者数据项还存在,虽说里面是空的了,但还是会占用一定的空间。


    注意,在使用 session_regenerate_id(); 时,要设置它的参数为 true ,也就是 session_regenerate_id(true); 这样,这个参数的意思就是删除老的 session id 内容。否则老的 session id 还是可以访问到数据的。


    同理,现在很多网站会做自动登录,对于每次登录之后,最好是刷新你的 Token 或者是 session id ,而且过一段时间也要让用户重新登录一次。毕竟这些登录信息也是保存在客户端的 Cookie 中的。除了相关的 Cookie 安全设置之外,还要根据用户的登录环境比如 IP 地址、浏览器的变化来及时地让自动登录失效,保证用户的帐号安全。另外,注意要让 Cookie 和 SESSION 的过期时间保持一致,让它们一起过期。

    安全选项配置

    在 php.ini 中,有一个 session.use_strict_mode 选项,在默认情况下它是关闭的。如果开启它的话,就可以让会话模块禁止使用未初始化的 session id 。也就是说,它只接受由当前系统自己创建的有效的 session id ,而拒绝由用户自己提供的 session id 。


    攻击者可以自行设置 Cookie 或者使用 JS 注入的方式来设置 session id 并进行会话攻击。启用 session.use_strict_mode 之后,可以阻止未经模块初始化的 session id 的执行。


    上面说的是什么意思呢?比如我们传递一个不是由我们系统生成的 session id 。然后系统并没有严格地验证用户登录情况,而是以这个 session id 进行新的初始化并附上一些数据的话,那么这个攻击就成功了。


    另外,如果确定我们当前的页面只是读取,比如说非登录页面。那么我们可以为当前的会话设置一个 read_and_close 属性,会话文件在读取完成之后会马上关闭。

    session_start(['read_and_close'=>true]);

    CSRF

    对于 SESSION 来说,CSRF 是无法防范的,但在 PHP7.3 之后增加了 Cookie 中的 SameSite 设置,也就是同源站点信息的设置,可以有效地防范此类攻击。当然,对于 CSRF 更方便地还是增加随机 Token 来验证,这个功能各类框架都已经提供了,这里也就不在多说了。

    核心重点功能的重验证

    最后,我们再来说一个问题。大家在使用很多应用的时候都会发现一个问题,特别是在涉及金钱交易的时候,都会让我们每次都输入一个交易密码。这其实是通过业务的手段来保证安全的一种形式。也不一定是完全的在涉及到金钱交易的时候才应用,比如我们后台如果检测到了用户登录的异常,IP 地址变化、浏览器网络环境的变化,那么即使他登录成功了,也只能做一些常规性的操作,而在重要的操作时,比如发表新的文章、查看核心的数据、删除用户或数据、修改数据的时候,重新进行一次简单的密码验证,也能够有效地对我们的系统用户安全进行保障。

    总结

    对于 SESSION 的安全来说,Cookie 其实才是最重要的一环。对于这点来说相信大家不会有异议。要说最核心的问题那只能说是 HTTP 是无状态的,实在是没有别的方法能够在不同的页面之间共享数据。Cookie 配合 SESSION 这种方式是最经济实惠而且也是最方便的一种方案。只要做好了相应的防护,基本上在我们的日常开发中还是不会有太大的问题的。安全从来都没有绝对一说,只有相对的安全。即使是大如阿里、腾讯之类的公司,也无时无刻的不在应对各种网络攻击威胁。不断地提升自己,学习各类安全防范知识才是我们进一步提升的关键。


    参考文档:


    https://www.php.net/manual/zh/features.session.security.management.php

    搜索
    关注