SSO,即单点登录,其作用是用户登录一遍之后可在几个不同应用之间实现登录态。如当你在 A 网站登录了之后,在 B 网站也是登录状态了。实现 SSO 的方法有很多,一个要点是需要有一个标示某个用户已经登录的凭证,且该凭证能够在多个系统之间共享。使用 Cookie 保存相关的信息是一个广泛被使用的方法。那么,如何做到登录网站 A 之后,B 网站也变成已登录状态呢?
假设 A 系统域名为example-a.com
,其登录页地址为 login.example-a.com
,B 系统域名为example-b.com
,当登录了 A 系统之后,B 系统也变为登录态,可以这样做:
login.example-a.com
登录Set-Cookie
头部,包含了对应的 token,将会将 Cookie 保存到 B 系统域名下这种 Cookie,被称为第三方 Cookie,这是在 A 系统域名下设置了 B 系统域名的 Cookie。不过,第三方 Cookie 是可以被限制的,如:
如果浏览器开启了这种配置,会导致上述的 SSO 方法失效。
此外,响应返回时最好带上 P3P 头部:
P3P: CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR
另一种方案是:
这样的方式就没有上面所说的第三方 Cookie 的困扰了,这里有一篇文章描述了阿里、京东 SSO 的每一个步骤。
谷歌有一个提案 draft-west-cookie-priority-00 - A Retention Priority Attribute for HTTP Cookies,提议给 Cookie 增加一个 Priority 属性,不过,目前也只有 Chrome 实现该提案。
我们知道,浏览器存储 Cookie 是有限的,不同的浏览器有不同的限制,如一些浏览器限制的是一个域名下 Cookie 的总数量以及单个 Cookie 的大小,一些浏览器限制的则是一个域名下所有 Cookie 的总大小等,并且,整个浏览器能保存的 Cookie 量也是有限制的,对于具体数据,你可以在这个网站详细查看。
当增加新 Cookie 将会导致 Cookie 超出存储上限的时候,浏览器会剔除旧的 Cookie 以容纳新 Cookie。
在不考虑这个提案实现的情况下,根据 RFC 6265 - HTTP State Management Mechanism,剔除 Cookie 的顺序如下:
其中还指出如果两个 Cookie 优先级相同的话,应剔除具有最早访问时间的 Cookie(在 Browser cookie restrictions 中提到 Firefox 触发 Cookie 剔除的时候采取随机的策略,但目前在最新版 Firefox 上没有这种现象)。
而根据上面 Priority 的提案,设置 Cookie 的时候可以指定一个 Priority 属性,Priority 可取的值为:
也就是说,我们可以像下面这样在设定 Cookie 时指定 Priority:
Set-Cookie: key=value; Priority=Medium;
提案要求实现该特性的客户端需要为每一种优先级的 Cookie 设定一个至少保留值。在移除 Cookie 的时候,执行如下策略(每一条都遵循 LRA 的策略剔除 Cookie):
举个例子,假设我们实现的一个客户端同一个域名最多可存储的 Cookie 上限为 12,至少保留 2 个优先级为 Low 的 Cookie,4 个优先级为 Medium 的 Cookie,2 个优先级为 High 的 Cookie,当触发 Cookie 逐出时,最终保留 8 个 Cookie,其结果如图所示:
实现 Priority 的 Cookie 触发移除时的演示
可以看到,从左到右第 1、3、4、5、7 的 Cookie 被删除了。
PS:对于某个域名 Cookie 超出限制时,Chrome 每次触发逐出后会保留该域名下 150 个 Cookie。
引入 Priority 的意义是,某些 Cookie 比另外的 Cookie 更加重要,如保存登录凭证的 Cookie 比保存用户某个偏好设置的 Cookie 更加重要,对于无关紧要的 Cookie,我们可以设置低优先级(Low),而对于重要的 Cookie,则可以设置高优先级(High)。
谷歌似乎对 Cookie 的优先级问题十分上心,在 2017 年又有一个提案draft-ietf-httpbis-rfc6265bis-02 - Cookies: HTTP State Management Mechanism,其 Cookie 移除策略如下:
目前 Chrome 对 Cookie 的实现是上面两种的混合,其优先级从低到高为:
Chrome 会按照从低到高的顺序最多进行 6 轮移除过程,当移除非 secure 的 Cookie 后已经到达对应优先级的至少保留值时,不会再去剔除对应优先级的 secure Cookie。
同样举上面那样限制的一个客户端实现的例子,其结果如下:
当前 Chrome 实现策略的一个示例
可以看到,在每个对应的 Priority 级别的 Cookie 里,非 secure 的 Cookie 会先于 secure Cookie 被逐出。
虽然这里详细描述了 Cookie 逐出的策略,但是超出浏览器限制也是比较少的现象,如果出现也需要考虑自己是否存在滥用 Cookie 的现象(如将调查问卷的答题情况全部保存在 Cookie 中这种行为)。