理解session和cookie

本文最后更新于:2023年12月5日 晚上

session 和 cookie 存在的目的是为了解决 http 协议的无状态

PHP 的 session 机制工作过程大致是这样的: 当客户端浏览器向服务器发起一个请求的时候,服务器会检查请求数据包头部中的“Cookie”字段是否包含名称为PHPSESSID的变量,

理解session和cookie1.png

这个名称可以通过 php.ini 中的 session.name 自定义,默认是 PHPSESSID,比如 https://nba.hupu.com/ 貌似就命名为_HUPUSSOID

理解session和cookie3.png

该变量的值即为 sessionid, 即:$_COOKIE[session.name]=sessionid。若不存在,PHP 会在 session.savepath 配置的路径目录下生成一个文件(session.save_path 也是 PHP 的配置文件 php.ini 中的一个配置项,配置服务器 session 文件放置的位置),同时生成一个 sessionid,这个文件的名称即为“sess”和 sessionid 拼凑而成。

理解session和cookie2.png然后在发送给浏览器的数据包头部中的 Set-Cookie 字段中指定 session 的名称和对应的 sessionid,浏览器则根据该字段的信息在内存中创建一个 Cookie,严格来说叫 SessionCookie。下一次浏览器再访问服务器的时候便会在数据包头部的 Cookie 字段中加入该 Cookie。若服务器发现浏览器请求包头部中“Cookie”字段包含了名为 session.name 的 sessionid,就会根据该 sessionid 到 session.savepath 指定的路径下找到名称为“sess”+sessionid 的文件,对文件进行读取或写入操作,开始了和客户端之间的会话。

由于 SessionCookie 是存在于浏览器内存中的,所以当浏览器关闭的时候,原来的 SessionCookie 也就消失了,下一次访问同一个服务器需要再次创建 session 文件和 Cookie,当然也有一些 cookie 是存储在客户端硬盘中的,即使关闭了浏览器,下一次打开浏览器访问相同网站的时候还是可以使用这个 cookie。当客户端的 cookie 过期之后,服务器中原来的 session 文件也就没有用处了。在 PHP 的配置文件 php.ini 中,使用配置项“session.gc_maxlifetime”来设置 session 文件的生存期,超过这个时间期限的文件数据都将被视为垃圾,并由垃圾回收程序处理。垃圾回收程序是在会话初始化时启动的,但并不是每一次都会启动,是有一定概率的,PHP 配置文件中使用“session.gc_probability”和“session.gc_divisor”这两个配置项来设置这个概率,计算公式为:session.gc_probability / session.gc_divisor。

以上讲述的是使用 Cookie 来存储 sessionid 的方法,这也是 PHP 默认的存储 sessionid 的方法。当客户端的 Cookie 出现问题的时候,如:用户设置浏览器禁用 cookie,session 就会受到影响了。不过我们可以通过其他方法来存储 sessionid,主要有以下三种方法:

  1. 设置文件 php.ini 中的 session.use_trans_sid = 1,可以让 PHP 自动跨页传递 sessionid(PHP 会自动把 sessionid 附着在 URL 末尾)。

  2. 手动通过 URL 传值,或通过隐藏表单字段传递 sessionid。

  3. 使用文件、数据库等形式保存 sessionid,在跨页过程中手动调用。

    注意,方法一配置 session.use_trans_sid=1 的同时也要配置 session.use_only_cookies=0,否则客户端禁用了 Cookie 之后即使置 session.use_trans_sid=1,session 还是无法使用。

在方法 2 中,第一次调用 session_start()函数时,PHP 会创建一个 session 文件并产生一个 sessionid,可以通过 session_id()函数获得该 sessionid,将 sessionid 拼接在 url 后面通过 get 方法传递(这种方法是存在很大的安全问题的),或者将 sessionid 作为表单的隐藏字段使用 post 方法传递,然后在下一个页面中可以把传过来的 sessionid 作为参数传递给 PHP 的 session_id()函数,指定要读写的 session 文件,然后调用 session_start()函数启动 session 会话,接下来就可以对 session 文件进行读取操作了。

必须说明的是,PHP 的 Session 机制并不是绝对安全的,攻击者如果能通过一定手段劫持、或者猜测出某个合法用户的 sessionid,那么属于这个用户的 session 数据都将暴露。所以,开发者应该设计一些方案来防御攻击者的攻击,提高 Session 机制的安全性,下面提供了一种利用请求数据包头部中的一些字段信息来加强 Session 安全性的方案思路。

将头部字段“User-Agent”和 sessionid 组合起来加密生成一个 token,并且让客户端在后续的请求中携带这个 token。为了更加保险,可使用两种不同的数据传递方式来 分别传递 sessionid 和 token,例如,通过 cookie 传递 sessionid,通过 get 方式传递 token。


理解session和cookie
http://blog.lujinkai.cn/PHP/基础/理解session和cookie/
作者
像方便面一样的男子
发布于
2020年12月9日
更新于
2023年12月5日
许可协议