HTTP 会话控制[Cookie与Session] - 学习/实践

1.应用场景

主要用于会话控制,学习理解高效正确使用Cookie与Session.

2.学习/操作

1. 文档阅读

https://blog.csdn.net/matthis_meng/article/details/80530927 // 一个浏览器最多可以产生多少个cookie,每个cookie 文件最大不能超过多少?

https://www.jianshu.com/p/9fb978b1d811  // 各浏览器Cookie大小、个数限制

https://www.cnblogs.com/mashil/p/6416364.html  // 各浏览器Cookie大小、个数限制

https://www.cnblogs.com/YangJieCheng/p/7268378.html  // 如何严格限制session在30分钟后过期!

https://www.cnblogs.com/jianqingwang/p/5839151.html // https://www.cnblogs.com/jianqingwang/p/5839151.html //删除与销毁session

PHP: 运行时配置 - Manual  // PHP手册 --- 推荐认真阅读

PHP session反序列化漏洞总结 // PHP session反序列化漏洞总结  -- 20210424 周六 公寓

29|Session与Cookie:账户体系的安全设计原理-极客时间 -- 推荐

会话管理 - 弄明白前后端接口 Cookie、Session、Token 的区别

2. 整理输出

2.1 Cookie

1). 简洁介绍

Cookie在远程浏览器端存储数据并以此跟踪和识别用户的机制.

从实现上来说, Cookie是存储在客户端上的一小段数据, 浏览器即客户端, 通过HTTP协议和服务器端进行Cookie交互.

2). Cookie独立于语言存在

也就是说, 不论是PHP还是JSP种下的Cookie, 其本质都是一样的, 客户端脚本JS都能读取到.

Cookie在很多语言中都有实现, 比如 PHP, ASP, Java, .Net. 严格来说, Cookie并不是由这些语言实现的, 而这些语言则是实现对Cookie的间接操作, 即发送HTTP指令, 浏览器收到指令便操作Cookie并返回给服务器.

因此, Cookie是由浏览器实现和管理的. 

关于Cookie的RFC文档主要有: RFC6265, RFC2109.

举例来说, 我们经常使用PHP设置Cookie, 但实际上PHP并没有真正地设置过Cookie, 甚至可以说, PHP根本没有能力去设置Cookie. 它只是发出命令让浏览器来做这件事而已, 形象地说就是和"有关部门"打个招呼. 了解这个概念, 对我们后面的学习很重要.

Cookie主要是参照RFC2109标准由客户端实现其生成, 使用等整个管理过程, 服务器端则参考此标准实现和客户端之间的交互指令.

3). 浏览器产生Cookie数量,每个Cookie文件大小

Cookie的总数量没有限制,但是每个域名的Cookie数量和每个Cookie的大小是有

限制的!

IE 每个域名限制为50 个。

Firefox 每个域名Cookie 限制为50 个。

Opera 每个域名Cookie限制为30 个。

Safari/webkit 貌似没有Cookie限制。但是假如Cookie很多,则会使header 大小超过服

务器的处理的限制,会导致错误发生。

不同浏览器间每个Cookie文件大小也不同

Firefox 和safari 是4097 个字节,包括名(name)、值(value)和等号。

Opera 是4096 个字节,包括:名(name)、值(value)和等号。

IE 是4095 个字节,包括:名(name)、值(value)和等号。

Note:

对于这个参数, 其实没那么重要, 毕竟来说是够用的, 另外, 如果需要确切的数据, 请到指定的浏览器官方文档查询确认

随便找一个网站,看Cookie和Sessioin信息

2.2 Session

1). 如何严格限制Session在30分钟后过期!

如何严格限制Session在30分钟后过期?
1. 设置客户端Cookie的lifetime为30分钟;
2. 设置Session的最大存活周期maxlifetime也为30分钟;
3. 为每个Session值加入时间戳,然后在程序调用时进行判断;

Note:

其实, 第二点可有可无, 毕竟第三点已经能确保~

至于为什么,我们首先来了解下PHP中Session的基本原理:

PHP中的Session有效期默认是1440秒(24分钟),也就是说,客户端超过24分钟没有刷新,当前Session就会失效。当然如果用户关闭了浏览器,会话也就结束了,Session自然也不存在了!

大家知道,Session储存在服务器端,根据客户端提供的SessionID来得到这个用户的文件,然后读取文件,取得变量的值,SessionID可以使用客户端的Cookie或者Http1.1协议的Query_String(就是访问的URL的“?”后面的部分)来传送给服务器,然后服务器读取Session的目录.
要控制Session的生命周期,首先我们需要了解一下php.ini关于Session的相关设置(打开php.ini文件,在“[Session]”部分):
1、session.use_cookies:默认的值是“1”,代表SessionID使用Cookie来传递,反之就是使用Query_String来传递;
2、session.name:这个就是SessionID储存的变量名称,可能是Cookie,也可能是Query_String来传递,默认值是“PHPSESSID”;
3、session.cookie_lifetime:这个代表SessionID在客户端Cookie储存的时间,默认是0,代表浏览器一关闭, SessionID就作废……就是因为这个所以Session不能永久使用!
4、session.gc_maxlifetime:这个是Session数据在服务器端储存的时间,如果超过这个时间,那么Session数据就自动删除!

还有很多的设置,不过和本文相关的就是这些了,下面开始讲如何设置Session的存活周期。
前面说过,服务器通过SessionID来读取Session的数据,但是一般浏览器传送的SessionID在浏览器关闭后就没有了,那么我们只需要人为的设置SessionID并且保存下来,不就可以……
如果你拥有服务器的操作权限,那么设置这个非常非常的简单,只是需要进行如下的步骤:
1, 把“session.use_cookies”设置为1,使用Cookie来储存SessionID,不过默认就是1,一般不用修改;
2, 把“session.cookie_lifetime”改为你需要设置的时间(比如一个小时,就可以设置为3600,以秒为单位);
3, 把“session.gc_maxlifetime”设置为和“session.cookie_lifetime”一样的时间;


在PHP的文档中明确指出,设定Session有效期的参数是session.gc_maxlifetime。

可以在php.ini文件中,或者通过ini_set()函数来修改这一参数。

问题在于,经过多次测试,修改这个参数基本不起作用,session有效期仍然保持24分钟的默认值。
由于PHP的工作机制,它并没有一个daemon线程,来定时地扫描Session信息并判断其是否失效。

当一个有效请求发生时,PHP会根据全局变量session.gc_probability / session.gc_divisor(同样可以通过php.ini或者ini_set()函数来修改)的值,来决定是否启动一个GC(Garbage Collector)。
默认情况下,session.gc_probability = 1,session.gc_divisor =100,也就是说有1%的可能性会启动GC。

GC的工作,就是扫描所有的session信息,用当前时间减去session的最后修
改时间(modified date),同session.gc_maxlifetime参数进行比较,如果生存时间已经超过gc_maxlifetime,就把该session删除。


到此为止,工作一切正常。

那为什么会发生gc_maxlifetime无效的情况呢?


在默认情况下Session信息会以文本文件的形式,被保存在系统的临时文件目录中。

在Linux下,这一路径通常为\tmp,在 Windows下通常为C:\Windows\Temp。

当服务器上有多个PHP应用时,它们会把自己的session文件都保存在同一个目录中。

同样地这些PHP应用也会按一定机率启动GC,扫描所有的session文件。

问题在于,GC在工作时,并不会区分不同站点的session。

举例言之

站点A的gc_maxlifetime设置为2小时,

站点B的 gc_maxlifetime设置为默认的24分钟。

当站点B的GC启动时,它会扫描公用的临时文件目录,把所有超过24分钟的Session文件全部删除掉,而不管它们来自于站点A或B。

这样,站点A的gc_maxlifetime设置就形同虚设了。
找到问题所在,解决起来就很简单了。

解决办法:

修改session.save_path参数,或者使用session_save_path()函数,把保存Session的目录指向一个专用的目录,gc_maxlifetime参数工作正常了。

还有一个问题就是,gc_maxlifetime只能保证Session生存的最短时间,并不能够保存在超过这一时间之后Session信息立即会得到删除。因为GC是按机率启动的,可能在某一个长时间内
都没有被启动,那么大量的Session在超过gc_maxlifetime以后仍然会有效。


解决这个问题的一个方法是,把session.gc_probability / session.gc_divisor的机率提高,如果提到100%,就会彻底解决这个问题,但显然会对性能造成严重的影响。

另一个方法是自己使用PHP实现,创建一个Session类,在Session写入时,把过期时间也写入。

读取时,根据过期时间判断是否已过期。// 目前的项目中似乎就是使用这种策略, 同时将Session存储在Redis中

demo.php

class Session{  
      
    /** 
     * 设置session 
     * @param String $name   session name 
     * @param Mixed  $data   session data 
     * @param Int    $expire 超时时间(秒) 
     */  
   
public static function set($name, $data, $expire=600){  
        $session_data = array();  
        $session_data['data'] = $data;  
        $session_data['expire'] = time()+$expire;  
        $_SESSION[$name] = $session_data;  
    }  
  
    /** 
     * 读取session 
     * @param  String $name  session name 
     * @return Mixed 
     */  
   
public static function get($name){  
        if(isset($_SESSION[$name])){  
            if($_SESSION[$name]['expire']>time()){  
                return $_SESSION[$name]['data'];  
            }else{  
                self::clear($name);  
            }  
        }  
        return
false;  
    }  
  
    /** 
     * 清除session 
     * @param  String  $name  session name 
     */  
   
private static function clear($name){  
        unset($_SESSION[$name]);  
    }  
  


session_start();  
  
$data = '123456';  
session::set('test', $data, 10);  
echo session::get('test'); // 未过期,输出  
sleep(10);  
echo session::get('test'); // 已过期

2). 删除与销毁Session

PHP学习笔记:删除与销毁Session- 简庆旺 - 博客园

3). 关于Session的存储和PHP的获取

sess_8kk3uhek69qc1qd2asmhdbeu1i

在docker容器中的文件形式

 __flash|a:1:{s:11:"postDeleted";i:-1;}captcha|O:11:"ArrayObject":4:{i:0;i:0;i:1;a:2:{s:6:"number";i:5;s:8:"lifetime";i:3600;}i:2;a:0:{}i:3;N;}captcha.number|i:5;captcha.lifetime|i:3600;postDeleted|s:40:"You have successfully deleted your post.";__id|s:3:"100";__authKey|s:10:"test100key";

这里存储的数据都是写入的测试数据,序列化后存储。

网页请求头中的cookie中sessionid

可以看到,key为PHPSESSID, value就是sessionid,

跟存储在服务器上的文件名有前缀区别,这只是服务的设置而已,依然能定位到某个会话的文件和信息

以及后端PHP获取的sessionid

额外,提醒一点:

即便是同一个用户,每次登陆,都是重新生成一个sessionid, 只要保证每次有的用就好了,而且相对来说更加安全。

后续补充

...

3.问题/补充

1. 如果把Cookie禁用, Session还能用吗?

可以, 只要能将SessionID传递到服务端即可, 比如可以通过query_string方式来传递

2. 不要将Cookie当作客户端的存储器来使用.

Cookie的中文译名叫 甜饼, 点心, Cookie 确实能给我们带来许多好的用户体验和方便的功能,

但Cookie不是越多越好, 它会增加带宽.

一旦Cookie被设置在域[根域名]下, 则请求该域名下的一个资源, 浏览器和服务器之间都可能存在Cookie的上行和下行流量,看似一个很小的Cookie, 在一个页面的请求中就可能产生十几KB的流量, 所以不要滥用Cookie. [可使用Fiddler进行抓包自行验证]

3. Cookie的存储位置

前面说Cookie是保存在客户端上一段数据,那么它究竟保存在什么地方呢?

有两种情况:

一种是保存在文件中, 一种是保存在内存中.

这两种情况的区别是什么呢?

每种浏览器的策略都不尽相同, 但都实现了对Cookie的管理. 

比如IE是每个域名下一个文本文件, 而Firefox是全部放在SQLite数据库中管理.

Firefox

C:\Users\1\AppData\Local\Mozilla\Firefox\Profiles\jmzd2oar.default  // 但是该目录下, 并没有cookies.sqlite的文件, 应该是Firefox做了加密的原因

IE/Firefox/Chrome等浏览器保存Cookie的位置 - 脚本小娃子 - 博客园

使用SQLite 3打开sqlite文件, 较新的Firefox对此文件进行了加密,  只有特定的API才能读取此文件, 但内容并没有改变.

关闭浏览器, Cookie并不会消失,除非设置该Cookie的expire为空, 即随着浏览器关闭而消失. 

有些Cookie没有设置过期时间, 随着浏览器关闭而消失, 即保存在内存中.

还有一种Cookie是Flash创建的, 成为 Flash Shard Object, 又称 Flash Cookie, 即使清空浏览器所有的隐私数据, 这类顽固的Cookie还会存在硬盘上.

因为它们不受浏览器管理, 只受Flash管理. 很多网站采用这种技术识别用户,最新浏览器, 如Firefox支持删除Flash创建的Cookie , 这是由于Adobe公司向Mozilla提供了对应的钩子.

Note:

最新的浏览器厂商们, 已经不支持Flash

Firefox 将结束对 Adobe Flash 的支持 | Firefox 帮助

4. 单点登录SSO与Cookie的关系

正常的Cookie只能在一个应用中共享, 即一个Cookie只能由创建它的应用获得,实现Cookie的跨域, 主要是为了统一应用平台, 即实现目前最流行的单点登录.

最简单的方式使用P3P协议. // Platform for Privacy Preferences 隐私首选项平台

单点登录 / SSO - 学习/实践_william_n的博客-CSDN博客

4.参考

参见文档阅读列表

后续补充

...

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值