会话控制的思想是指能够在网站中根据一个会话跟踪用户,下面是小编整理的PHP中使用会话控制,希望大家喜欢。
1、什么是会话控制
HTTP是一种无状态协议,它的内部没有一个内建机制来维护两个事务之间的状态。当一个用户在请求一个页面后再请求另一个页面,HTTP将无法告诉我们这两个请求时来自同一个用户。
2、理解基本的会话功能
PHP的会话是通过唯一的会话ID来驱动的,会话ID是一个加密的随机数字。它由PHP生成,在会话的生命周期中会保存在客户端,它可以保存在用户机器里的cookie中,或者通过URL在网络上传递。
会话ID就像一把钥匙,它允许我们注册一些特定的变量,也成为会话变量。这些变量的内容会保存在服务器端。会话ID是客户端唯一可见信息。如果在一次特定的网站链接中,客户端可以通过cookie或URL看到会话ID,那么我们就可以访问该会话保存在服务器中的会话变量。在默认情况下,会话变量保存在服务器上的普通文件中。
把会话ID保存在URL中,如果在URL中有一串看起来像随机数字的字符串,可能它就是某种形式的会话控制。
cookie是与会话不同的解决方案,它也解决了在多个事务之间保持状态的问题,同时还可以保持一个整洁的URL。
3、什么是Cookie
cookie是在服务器端被创建并写回到客户端浏览器,浏览器接到响应头中关于写cookie的指令则在本地临时文件夹中。创建了一个cookie文件,其中保存了你的cookie内容,cookie内容的存储是键值对的方式,键和值都只能是字符串。
cookie其实就是一小段信息,它可以由脚本在客户端机器保存。可以通过发送一个包含特定数据并且具有如下格式的HTTP标题头,从而在用户端机器设置一个cookie:
Set-Cookie:NAME=VALUE;[expires=DATE;][path=PATH;][domain=DOAMIN_NAME;][secure]
这会创建一个名为NAME,值为VALUE的cookie。除了该参数,其它参数都是可选的。expires域设置该cookie的失效日期(如果不设置失效日期将永远有效,除非手动删除)。path和domain域结合起来制定URL或与cookie有关的URL。secure的关键字的意思是在普通的HTTP连接中不发动cookie。
4、什么是Session
在session会话期间,session会分别保存在客户端和服务器端两个文件,客户端可以是cookie方式保存的sessionID(默认的保存方式)或通过url字符串形式传递。服务器端一般以文本的形式保存在指定的session目录中。在服务器端我们可以通过session.use_cookies来控制客户端使用哪一种保存方式。如果定义为cookie保存方式,我们可以通过session.cookie_lifetime(默认值0,闭浏览器就清除)来控制被保存在client上的cookie的有效期。而如果客户端用cookie方式保存的sessionID,则使用“临时”的cookie保存(cookie的名称为PHPSESSID,通过Firebug你可以了解到详细的信息,该名称你可以通过php.inisession.name进行更改),用户提交页面时,会将这一SessionID提交到服务器端,来存取session数据。这一过程,是不用开发人员干预的。
5、SESSION和COOKIE的区别与联系
相同点:都可以在解决HTTP无状态的问题,使同一个客户端在访问网站的多次请求中,可以保存,设置信息,并且在请求事物之间建立联系。
不同点:简单的说cookie的信息保存在客户端,session的信息保存在服务器端。
联系:当客户端使用基于Cookie方式保存的SessionID时,SessionID一般保存在cookie中。
备注:cookie在相同内核的浏览器之间是共享的,不同内核浏览器是不共享的例如火狐和IE(存放位置都不同,当然不共享)。不同内核浏览器不能共享cookie,也会产生不同sessionid。
会话管理基础
会话安全
会话模块无法保证你存储在会话中的信息只能被创建会话的用户本人可见。你需要采取额外的手段来保护会话中的机密信息,至于采取何种方式来保护机密信息,取决于你在会话中存储的数据的机密程度。
评估会话中存储的数据的重要性,以及为此增加额外的保护机制,通常需要付出一定的代价,同时会降低便利性。例如,如果你需要保护用户免受社会工程学攻击,你需要启用session.use_only_cookies选项。这就要求用户在使用过程中,必须把浏览器设置为接受cookie,否则就无法正常使用会话功能了。
有很多种方式都可以导致会话ID被泄露给第三方。例如,JavaScript注入,URL中包含会话ID,数据包侦听,或者直接访问你的物理设备等。如果会话ID被泄漏给第三方,那么他们就可以访问这个会话ID可以访问的全部资源。首先,如果在URL中包含了会话ID,并且访问了外部的站点,那么你的会话ID可能在外部站点的访问日志中被记录(referrer请求头)。另外,攻击者也可以监听你的网络通信,如果通信未加密,那么会话ID将会在网络中以明文的形式进行传输。针对这种情况的解决方案就是在服务端配置SSL/TLS,另外,使用HSTS可以达到更高的安全性。
注意:即使使用HTTPS协议,也无法百分百保证机密数据不被泄漏。例如,CRIME和BEAST漏洞可以使得攻击者读取到你的数据。另外,出于网络通信审计目的,很多网络中都存在HTTPSMITM代理,可以读取HTTPS协议下的通信数据。那么攻击者也可以搭建类似的代理服务器,用来窃取HTTPS协议下的通信数据。
非自适应会话管理
目前,默认情况下,PHP是以自适应的方式来管理会话的,这种方式使用起来很灵活,但是同样也带来了一定的风险。
警告
用户自定义的会话存储器也可以通过实现会话ID验证来支持严格会话模式。建议用户在实现自己的会话存储器的时候,一定要对会话ID的合法性进行验证。
在浏览器一侧,可以为用来保存会话ID的cookie设置域,路径,仅允许HTTP访问,必须使用HTTPS访问等安全属性。如果使用的是PHP7.3.版本,还可以对cookie设置SameSite属性。攻击者可以利用浏览器的这些特性来设置永久可用的会话ID。仅仅设置session.use_only_cookies配置项无法解决这个问题。而session.use_strict_mode配置项可以降低这种风险。设置session.use_strict_mode=On,来拒绝未经初始化的会话ID。
对过期会话数据的访问并不总是意味着正在遭受攻击。不稳定的网络状况,或者不正确的会话删除行为,都会导致合法的用户产生访问过期会话数据的情况。
从PHP7.1.0开始,增加了session_create_id()函数。这个函数允许开发者在会话ID中增加用户ID作为前缀,以确保用户访问到正确对应的会话数据。要使用这个函数,请确保启用了session.use_strict_mode配置项,否则恶意用户可能会伪造其他用户的会话ID。
重新生成会话ID
虽然session.use_strict_mode配置项可以降低风险,但是还不够。为了确保会话安全,开发者还需要使用session_regenerate_id()函数。
会话ID重生机制可以有效的降低会话被窃取的风险,所以,必须周期性的调用session_regenerate_id()函数来重新生成会话ID,例如,对于机密内容,每隔15分钟就重新生成会话ID。这样一来,即使会话ID被窃取,那么攻击者所得到的会话ID也会很快的过期,如果他们进一步访问,就会产生对过期会话数据访问的错误。
当用户成功通过认证之后,必须为其重新生成会话ID。并且,必须在向$_SESSION中保存用户认证信息之前调用session_regenerate_id()函数(session_regenerate_id()函数会自动将重生之前的会话数据保存到新生成的会话)。请确保只有新的会话包含用户认证信息。
开发者不可过分依赖session.gc_maxlifetime配置项。因为攻击者可以在受害者的会话过期之前访问系统,并且维持这个会话的活动,以保证这个会话不会过期。
删除活跃会话可能会带来非预期的一些影响。例如,在网络状态不稳定,或者有并发请求到达Web服务器的情况下,立即删除活跃会话可能导致个别请求会话失效的问题。
立即删除活跃会话也无法检测可能存在的恶意访问。
在调用session_regenerate_id()函数之后,不能立即禁止对旧的会话数据的访问,应该再一小段之间之后再禁止访问。例如,在稳定的网络条件下,可以设置为几秒钟,在不稳定的网络条件下,可以设置为几分钟。
如果用户访问了旧的会话数据(已经过期的),那么应该禁止访问。建议从会话中移除这个用户的认证信息,因为这看起来像是在遭受攻击。
如果攻击者设置了不可删除的cookie,那么使用session.use_only_cookies和session_regenerate_id()会导致正常用户遭受拒绝服务的问题。如果发生这种情况,请让用户删除cookie并且警告用户他可能面临一些安全问题。攻击者可以通过恶意的Web应用、浏览器插件以及对安全性较差的物理设备进行攻击来伪造恶意的cookie。
请勿误解这里的拒绝服务攻击风险所指的含义。通常来讲,要保护会话ID的安全,session.use_strict_mode=On是必须要做的。建议所有的站点都启用session.use_strict_mode。
只有当账号处于被攻击的时候,才会发生拒绝服务的问题。通常都是由于应用中被注入了恶意的JavaScript才会导致这个问题。
会话中数据的删除
过期的会话中的数据应该是被删除的,并且不可访问。现在的会话模块尚未很好的支持这种特性。
会话和锁定
默认情况下,为了保证会话数据在多个请求之间的一致性,对于会话数据的访问是加锁进行的。
当会话不活跃的时候,当前的会话模块不会检测对于$_SESSION的修改。你需要自己来保证在会话处于不活跃状态的时候,不要去修改它。
活跃会话
有很多种方式可以做到追踪用户的活跃会话。你可以通过在数据库中存储会话信息来跟踪用户会话。由于会话是可以被垃圾收集器收集掉的,所以你也需要处理被收集掉的会话数据,以保证数据库中的数据和真实的活跃会话数据的一致性。
一种很简单的方式就是使用“使用用户ID作为会话ID前缀”,并且保存必要的信息到$_SESSION中。大部分的数据库产品对于字符串前缀查询(译注:也即右模糊查询,可以利用索引)都有很好的性能表现。为了实现这种方式,可以使用session_regenerate_id()和session_create_id()函数。
永远不要使用机密数据作为会话ID前缀!如果用户ID属于机密数据,那么可以考虑使用hash_hmac()函数对其进行摘要后再使用。
必须启用session.use_strict_mode配置项。请确保已经启用,否则活跃会话数据库可能会被入侵。
CSRF(跨站请求伪造)
会话和认证无法避免跨站请求伪造攻击。开发者需要自己来实现保护应用不受CSRF攻击的功能。
output_add_rewrite_var()函数可以用来保护应用免受CSRF攻击。更多信息请参考文档。
注意:PHP7.2.0之前的版本,这个函数和会话ID使用了同样的输出缓冲以及INI设置项,所以不建议在PHP7.2.0之前使用output_add_rewrite_var()函数。
大部分Web应用框架都提供了CSRF保护的特性。详细信息请参考你所用的Web框架的文档。
从PHP7.3开始,对于会话cookie增加了SameSite属性,这个属性可以有效的降低CSRF攻击的风险。