面试常问的Session相关问题.
Session和Cookie的关系?
Cookie是什么?
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息。
如何识别特定的客户呢?cookie就可以做到。每次HTTP请求时,客户端都会发送相应的Cookie信息到服务端。
它的过期时间可以任意设置,如果你不主动清除它,在很长一段时间里面都可以保留着,即便这之间你把电脑关机了。
Session是什么?
Session是在无状态的HTTP协议下,服务端记录用户状态时用于标识具体用户的机制。
它是在服务端保存的用来跟踪用户的状态的数据结构,可以保存在文件、数据库或者集群中。
在浏览器关闭后这次的Session就消失了,下次打开就不再拥有这个Session。
其实并不是Session消失了,而是Session ID变了,服务器端可能还是存着你上次的Session ID及其Session 信息,
只是他们是无主状态,也许一段时间后会被删除。
关系?
Cookie 在客户端(浏览器),Session 在服务器端。
Cookie的安全性一般,他人可通过分析存放在本地的Cookie并进行Cookie欺骗。在安全性第一的前提下,选择Session更优。
重要交互信息比如权限等就要放在Session中,一般的信息记录放Cookie就好了。
3.单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie
Session 可以放在 文件、数据库或内存中,比如在使用Node时将Session保存在redis中。由于一定时间内它是保存在服务器上的,
当访问增多时,会较大地占用服务器的性能。考虑到减轻服务器性能方面,应当适时使用Cookie。Session 的运行依赖Session ID,而 Session ID 是存在 Cookie 中的,也就是说,如果浏览器禁用了 Cookie,Session 也会失效
(但是可以通过其它方式实现,比如在 url 中传递 Session ID)用户验证这种场合一般会用 Session。因此,维持一个会话的核心就是客户端的唯一标识,即Session ID
禁用了Cookie还可以继续使用Session吗? 如何使用?
如果客户端的浏览器禁用了 Cookie 怎么办?建议使用URL重写技术进行会话跟踪,
即每次HTTP交互,URL后面都被附加上诸如 sid=xxxxx 的参数,以便服务端依此识别用户。
面试的时候经常被问到Cookie禁用了,Session还能用吗?
默认SESSION配置
在默认的PHP配置中,SessionID是需要存储在Cookie中的,默认Cookie名为:
PHPSESSIONID
以下以PHP为例:
1 | 1. 你第一次访问网站时, |
如果客户端禁用了Cookie,那PHPSESSIONID
都无法写入客户端,Session还能用?
答案显而易见:不能
并且服务端因为没有得到
PHPSESSIONID
的cookie,会不停的生成session_id
文件
取巧传递session_id
但是这难不倒服务端程序,聪明的程序员想到,如果一个Cookie都没接收到,基本上可以预判客户端禁用了Cookie,
那将session_id附带在每个网址后面(包括POST),比如:
1 | GET http://www.xx.com/index.php?session_id=xxxxx |
然后在每个页面的开头使用session_id($_GET['session_id'])
,来强制指定当前session_id
这样,答案就变成了:能
但是这样做的方式是不可取的。为什么?因为有风险!
聪明的你肯定想到,那将这个网站发送给别人,那么他将会以你的身份登录并做所有的事情(目前很多订阅公众号就将openid附带在网址后面,这是同样的漏洞)。
其实不仅仅如此,cookie也可以被盗用,比如XSS注入,通过XSS漏洞获取大量的Cookie,也就是控制了大量的用户,腾讯有专门的XSS漏洞扫描机制,因为大量的QQ盗用,发广告就是因为XSS漏洞
所以Laravel等框架中,内部实现了Session的所有逻辑,并将PHPSESSIONID设置为httponly并加密,这样,前端JS就无法读取和修改这些敏感信息,降低了被盗用的风险。
如何实现Session共享?
为什么要session共享?
现在稍微大一点的网站基本上都有好几个子域名,比如www.caoxl.com
, search.caoxl.com
, member.caoxl.com
,这些网站如果需要共用用户登录信息,那么就需要做到session共享,当然前提是有相同的主域。
要解决session共享,就必须解决两个问题:
- 多台服务器用同一个session_id
这个比较容易解决,只要在php中设置存session_id的cookie域名为网站主域就可以了
打开PHP.ini, 设置session.cookie_domain = .caoxl.com
,
当然也可以在php代码当中设置ini_set("session.cookie_domain","caoxl.com");
- 多台服务器用同一个session_id访问到相同的session内容
要实现这点,就必须把session内容存储到让所有服务器都能访问到的地方,php的session内容是默认存储到本服务器的文件中的,一般的解决方案是存入数据库,memcache或者redis这种缓存服务器,
当然用默认的文件存储方式也可以,用NFS统一存储。