客户端识别与 cookie 机制

前言

HTTP 最初是一个匿名、无状态的请求/响应协议。服务器处理来自客户端的请求,
然后向客户端会送一条响应。Web 服务器几乎没有什么信息可以用来判定是哪个用
户发送的请求,也无法记录来访用户的请求序列。

而现在越来越多的情况,我们的 Web 站点希望能够提供个性化的接触,希望对连接
另一端的用户有更多的了解,并且能在用户浏览页面时对其最终。

本文对 HTTP 识别用户的几种方式进行了总结。需要知道的是,每种技术都有优劣。

常见的方式有:

  • HTTP 头部。根据承载用户身份信息的 HTTP 头部信息进行判断
  • 客户端 IP 地址跟踪。通过用户的 IP 地址对其进行识别
  • 胖 URL。一种在 URL 中嵌入识别信息的技术
  • cookie。一种功能强大且高效的持久身份识别技术
  • 用户登录。用认证的方式来识别用户

HTTP 头部

七种最常见的用来承载用户相关信息的 HTTP 请求头部如下:

  • From 用户的 E-mail 地址
  • User-Agent 用户的浏览器软件
  • Referer 用户是从哪个页面上依照链接跳转过来的
  • Authorization 用户名和密码
  • ClientIP(扩展) 用户的 IP 地址
  • X-Forwarded-For(扩展) 用户的 IP 地址
  • Cookie(扩展) 服务器产生的 ID 标签

这里先说明前三个:

From

From 头部包含了用户的 E-mail 地址。

每个用户都有不同的 E-mail 地址,所以咋理想情况下,可以将这个地址作为可行的源端来识别用户。
但由于担心那些不道德的服务器会搜集这些 E-mail 地址,用于垃圾邮件的散发,
所以很少有浏览器会发送 From 头部。

实际上,From 头部是由自动化的机器人或蜘蛛发送的,这样在出现问题时,网管还有个地方可以发送
愤怒的邮件。

User-Agent

User-Agent 头部可以将用户所用浏览器的相关信息告知服务器,包括程序的名称和版本,通常还包括
操作系统的相关信息。

要实现定制内容与特定的浏览器及其属性间有良好互操作时,这个头部是很有用的,但它并没有为识别特
定的用户提供太多有意义的帮助。

Referer

Referer 头部提供了用户来源页面的 URL。

Referer 头部自身并不能完全标识用户,但它却可以说明用户之前访问过哪个页面。

通过它可以更好的理解用户的浏览行为,以及用户的兴趣所在

结论

综上,From、User-Agent、Referer都不足以实现可靠的识别。


客户端 IP 地址

还没开始往下看,或许就知道了这个方案的可行性了。结论是:最好不要使用这种方案。
无法用 IP 地址确定目标的地方太多了。

少数站点甚至将客户端 IP 地址作为一种安全特性使用,它们只向来自特定 IP 地址的用户提供文档。
在内部网络中或许可以这么做,但是在因特网上就不行了,主要是因为因特网上 IP 地址太容易伪造了。
路径上如果有拦截代理,也会破坏此方案。


胖 URL (fat URL)

有些 Web 站点会为每个用户生成特定的 URL 来追踪用户的身份。通常,会对真正的 URL 进行扩展,
在 URL 路径开始或结束的地方添加一些状态信息。用户浏览站点时,Web 服务器会动态生成一些超链接,
继续维护 URL 中的状态信息。

改动后包含了用户在状态信息的 URL 被称为胖 URL。

可以通过胖 URL 将 Web 服务器上若干个独立的事务捆绑成一个“会话”或“访问”。用户首次访问这个 Web
站点时,会生成一个唯一的ID,用服务器可以识别的方式将这个 ID 添加到 URL 中去,然后服务器就会将
客户端重新导向这个胖 URL。不论什么时候,只要服务器收到了对胖 URL 的请求,就可以去查找与那个用户
ID 相关的所有增量状态(购物车、简介等),然后重写所有的输出超链,使其成为胖 URL,用以维护用户的 ID。

该方案存在几个严重的问题:

  • 丑陋的 URL
  • 无法共享 URL
  • 破坏缓存
  • 额外的服务器负荷
  • 逃逸口(用户很容易跳出)
  • 在会话间是非持久的

cookie

cookie 是目前识别用户,实现持久会话的最好方式。

cookie 非常重要,而且它们定义了一些新的 HTTP 头部。
cookie 的存在也影响了缓存,大多数缓存和浏览器都不允许对任何 cookie 的内容进行缓存。

可以笼统的将 cookie 分为两类:会话 cookie 和持久 cookie。

会话 cookie 是一种临时 cookie,它记录了用户访问站点时的设置和偏好。用户退出浏览器时,
会话 cookie 就被删除了。

持久 cookie 的生存时间更长一些,它们存储在硬盘上,浏览器退出、计算机重启时它们依然存在。
通常用持久 cookie 维护某个用户会周期性访问的站点的配置文件或登录名。

会话 cookie 和 持久 cookie 之间唯一的区别就是它们的过期时间。
如果设置了 Discard 参数,或者没有设置 Expires 或 Max-Age 参数来说明扩展的过期时间,
这个 cookie 就是一个会话 cookie。

cookie 就像服务器给用户贴的“嗨,我叫XXX”的贴纸一样。用户访问一个 Web 站点时,这个
Web 站点就可以读取服务器贴在用户身上的所有贴纸。

用户首次访问 Web 站点时,Web 服务器对用户一无所知。Web 服务器希望这个用户会再次回来,所以
想给这个用户“拍上”一个独有的 cookie,这样以后他就可以识别出这个用户了。cookie 中包含了一个
由 名字=值(name=value) 这样的信息构成的任意列表,并通过 Set-Cookie 或 Set-Cookie2
HTTP 响应头部将其贴到用户身上去。

cookie 中可以包含任意信息,但它们通常都只包含一个服务器为了进行跟踪而产生的独特的识别码。

浏览器会记住从服务器返回的 Set-Cookie 或 Set-Cookie2 头部中的 cookie 内容,并将 cookie集
存储在浏览器的 cookie 数据库中。将来用户访问同一个站点时,浏览器会挑中该站点服务器贴到用户身上
的那些 cookie,并在一个 cookie 请求头部中将其给服务器传过去。

cookie罐:客户端的状态

cookie 的基本思想就是让浏览器积累一组服务器特有的信息,每次访问服务器都将这些信息提供给它。
因为浏览器要负责存储 cookie 的信息,所以此系统被称为客户端侧状态(client-side state)。
这个 cookie 规范的正式名称为 HTTP 状态管理机制(HTTP state management mechanism)。

浏览器内部的 cookie 罐中可以有成百上千个 cookie,但浏览器不会将每个 cookie 都发送给所有的站点。

浏览器只会向服务器发送该服务器产生的那些 cookie。

domain

产生 cookie 的服务器可以向 Set-Cookie 响应头部添加一个 Domain 属性来控制哪些站点可以看到其
设置的 cookie。

Set-Cookie: user="lizhiyao"; domian="lizhiyao.me"

path

可以通过 Path 属性将 cookie 与 Web 站点的部分页面关联起来。


用户登录

参考

《HTTP 权威指南》

志遥 wechat
微信扫一扫,我在丁香园记公众号等你