HTTP Cookies详解

导读 HTTP cookies,通常称之为“cookie”,已经存在很长时间了,但是仍然没有被充分理解。首要问题是存在许多误解,认为 cookie 是后门程序或病毒,却忽视了其工作原理。第二个问题是,对于 cookie 的操作缺少统一的接口。尽管存在这些问题,cookie 仍旧在 Web 开发中扮演者重要的角色,以至于如果没有出现相应的代替品就消失的话,我们许多喜欢的 Web 应用将变的不可用。
cookie的起源?

早期的 Web 应用面临的最大问题之一就是如何维持状态。简言之,服务器无法知道两个请求是否来自于同一个浏览器。当时,最简单的办法就是在请求的页面中插入一个 token,然后在下次请求时将这个 token 返回至服务器。这需要在页面的 form 表单中插入一个包含 token 的隐藏域,或者将 token 放在 URL 的 query 字符串中来传递。这两种方法都需要手动操作,而且极易出错。

当时网景通讯的一名员工 Lou Montulli,在 1994 年将 “magic cookies” 的概念应用到 Web 通讯中。他试图解决 Web 的第一个购物车应用,现在购物车成了购物网站的支柱。他的原始说明文档提供了 cookie 工作原理的基本信息,该文档后来被作为规范纳入到 RFC 2109(大多数浏览器的实现参考文档)中,最终被纳入到 RFC 2965 中。Montulli 也被授予 cookie 的美国专利。网景浏览器在它的第一个版本中就开始支持 cookie,现在所有Web浏览器都支持 cookie。

cookie是什么?

简单地说,cookie 就是浏览器储存在用户电脑上的一小段文本文件。cookie 是纯文本格式,不包含任何可执行的代码。一个 Web 页面或服务器告知浏览器按照一定规范来储存这些信息,并在随后的请求中将这些信息发送至服务器,Web 服务器就可以使用这些信息来识别不同的用户。大多数需要登录的网站在用户验证成功之后都会设置一个 cookie,只要这个 cookie 存在并可以,用户就可以自由浏览这个网站的任意页面。再次说明,cookie 只包含数据,就其本身而言并不有害。

创建cookie

Web服务器通过发送一个称为 Set-Cookie 的 HTTP 消息头来创建一个 cookie,Set-Cookie 消息头是一个字符串,其格式如下(中括号中的部分是可选的):

Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]

消息头的第一部分,value 部分,通常是一个 name=value 格式的字符串。事实上,这种格式是原始规范中指定的格式,但是浏览器并不会对 cookie 值按照此格式来验证。实际上,你可以指定一个不含等号的字符串,它同样会被存储。然而,最常用的使用方式是按照 name=value 格式来指定 cookie 的值(大多数接口只支持该格式)。

当存在一个cookie,并允许设置可选项,该 cookie 的值会在随后的每次请求中被发送至服务器,cookie 的值被存储在名为 Cookie 的 HTTP 消息头中,并且只包含了 cookie 的值,忽略全部设置选项。例如:

Cookie: value

通过 Set-Cookie 指定的可选项只会在浏览器端使用,而不会被发送至服务器端。发送至服务器的 cookie 的值与通过 Set-Cookie 指定的值完全一样,不会有进一步的解析或转码操作。如果请求中包含多个 cookie,它们将会被分号和空格分开,例如:

Cookie: value1; value2; name1=value1

服务器端框架通常包含解析 cookie 的方法,可以通过编程的方式获取 cookie 的值。

cookie编码

对于 cookie 的值进行编码一直都存在一些困惑。普遍认为 cookie 的值必须经过 URL 编码,但其实这是一个谬论,尽管通常都这么做。原始规范中明确指出只有三个字符必须进行编码:分号、逗号和空格,规范中还提到可以进行 URL 编码,但并不是必须,在 RFC 中没有提及任何编码。然而,几乎所有的实现都对 cookie 的值进行了一系列的 URL 编码。对于 name=value 格式,通常会对 name 和 value 分别进行编码,而不对等号 = 进行编码操作。

cookie过期时间选项

紧跟cookie值后面的每个选项都以分号和空格分开,每个选择都指定了 cookie 在什么情况下应该被发送至服务器。第一个选项是过期时间(expires),指定了 cookie 何时不会再被发送至服务器,随后浏览器将删除该 cookie。该选项的值是一个 Wdy, DD-Mon-YYYY HH:MM:SS GMT 日期格式的值,例如:

Set-Cookie: name=Nicholas; expires=Sat, 02 May 2009 23:38:25 GMT

没有设置 expires 选项时,cookie 的生命周期仅限于当前会话中,关闭浏览器意味着这次会话的结束,所以会话 cookie 仅存在于浏览器打开状态之下。这就是为什么为什么当你登录一个 Web 应用时经常会看到一个复选框,询问你是否记住登录信息:如果你勾选了复选框,那么一个 expires 选项会被附加到登录 cookie 中。如果 expires 设置了一个过去的时间点,那么这个 cookie 会被立即删掉。

cookie的属性

domain选项

下一个选项是 domain,指定了 cookie 将要被发送至哪个或哪些域中。默认情况下,domain 会被设置为创建该 cookie 的页面所在的域名,所以当给相同域名发送请求时该 cookie 会被发送至服务器。例如,本博中 cookie 的默认值将是 bubkoo.com。domain 选项可用来扩充 cookie 可发送域的数量,例如:

Set-Cookie: name=Nicholas; domain=nczonline.net

像 Yahoo! 这种大型网站,都会有许多 name.yahoo.com 形式的站点(例如:my.yahoo.com, finance.yahoo.com 等等)。将一个 cookie 的 domain 选项设置为 yahoo.com,就可以将该 cookie 的值发送至所有这些站点。浏览器会把 domain 的值与请求的域名做一个尾部比较(即从字符串的尾部开始比较),并将匹配的 cookie 发送至服务器。domain选项的值必须是发送 Set-Cookie 消息头的主机名的一部分,例如我不能在 google.com 上设置一个 cookie,因为这会产生安全问题。不合法的 domain 选择将直接被忽略。

path选项

另一个控制 Cookie 消息头发送时机的选项是 path 选项,和 domain 选项类似,path 选项指定了请求的资源 URL 中必须存在指定的路径时,才会发送Cookie 消息头。这个比较通常是将 path 选项的值与请求的 URL 从头开始逐字符比较完成的。如果字符匹配,则发送 Cookie 消息头,例如:

Set-Cookie:name=Nicholas;path=/blog

在这个例子中,path 选项值会与 /blog,/blogrool 等等相匹配;任何以 /blog 开头的选项都是合法的。需要注意的是,只有在 domain 选项核实完毕之后才会对 path 属性进行比较。path 属性的默认值是发送 Set-Cookie 消息头所对应的 URL 中的 path 部分。

secure选项

最后一个选项是 secure。不像其它选项,该选项只是一个标记而没有值。只有当一个请求通过 SSL 或 HTTPS 创建时,包含 secure 选项的 cookie 才能被发送至服务器。这种 cookie 的内容具有很高的价值,如果以纯文本形式传递很有可能被篡改,例如:

Set-Cookie: name=Nicholas; secure

事实上,机密且敏感的信息绝不应该在 cookie 中存储或传输,因为 cookie 的整个机制原本都是不安全的。默认情况下,在 HTTPS 链接上传输的 cookie 都会被自动添加上 secure 选项。

cookie使用失效日期

当 cookie 创建时指定了失效日期,这个失效日期则关联了以 name-domain-path-secure 为标识的 cookie。要改变一个 cookie 的失效日期,你必须指定同样的组合。当改变一个 cookie 的值时,你不必每次都设置失效日期,因为它不是 cookie 标识信息的组成部分。例如:

Set-Cookie:name=Mike;expires=Sat,03 May 2025 17:44:22 GMT

现在已经设置了 cookie 的失效日期,所以下次我想要改变 cookie 的值时,我只需要使用它的名字:

Set-Cookie:name=Matt

cookie 的失效日期并没有改变,因为 cookie 的标识符是相同的。实际上,只有你手工的改变 cookie 的失效日期,否则其失效日期不会改变。这意味着在同一个会话中,一个会话 cookie 可以变成一个持久化 cookie(一个可以在多个会话中存在的),反之则不可。为了要将一个持久化 cookie 变为一个会话 cookie,你必须删除这个持久化 cookie,这只要设置它的失效日期为过去某个时间之后再创建一个同名的会话 cookie 就可以实现。

需要记得的是失效日期是以浏览器运行的电脑上的系统时间为基准进行核实的。没有任何办法来来验证这个系统时间是否和服务器的时间同步,所以当服务器时间和浏览器所处系统时间存在差异时这样的设置会出现错误。

cookie自动删除

cookie 会被浏览器自动删除,通常存在以下几种原因:

1)会话 cooke (Session cookie) 在会话结束时(浏览器关闭)会被删除。

2)持久化 cookie(Persistent cookie)在到达失效日期时会被删除。

3)如果浏览器中的 cookie 数量达到限制,那么 cookie 会被删除以为新建的 cookie 创建空间。详见我的另外一篇关于 cookies restrictions 的博客。

对于自动删除来说,Cookie 管理显得十分重要,因为这些删除都是无意识的。

总结

为了高效的利用 cookie,仍旧有许多要了解和弄明白的东西。对于一项创建于十多年前但仍旧如最初实现的那样被使用至今的技术来说,这是件多不可思议的事。本篇只是提供了一些每个人都应该知道的关于浏览器 cookie 的基本指导,但无论如何,也不是一个完整的参考。对于今天的 Web 来说 cookie 仍旧起着非常重要的作用,并且不恰当的管理 cookie 会导致各种各样的问题,从最糟糕的用户体验到安全漏洞。我希望这篇手册能够激起一些关于 cookie 的不可思议的亮点。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/linux/119275.html

(0)
上一篇 2021年8月28日 07:48
下一篇 2021年8月28日 07:48

相关推荐

发表回复

登录后才能评论