HTTP Cookie

HTTP Cookie( 也叫Web Cookie 或 浏览器 Cookie) 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie使基于无状态的HTTP协议记录稳定的状态信息成为了可能。

Cookie主要用于以下三个方面:

  • 会话状态管理 (如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

Cookie曾一度用户客户端数据的存储,因当时没有其他合适的存储办法而作为惟一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie渐渐被淘汰。由于服务器指定Cookie后,浏览器的每次请求都会携带Cookie数据,会带来额外的性能开销(尤其是在移动环境下)。新的浏览器API已经允许开发者直接将数据存储到本地,如使用Web storage API(localStorage&sessionStorage)或IndexedDB。

Cookie的构成:

cookie由浏览器保存的以下几块信息构成

  1. 名称(cookie-name):一个唯一确定的cookie的名称。cookie名称是不区分大小写的,所以myCookie和MyCookie被认为是同一个cookie。建议将cookie名称看作是区分大小写的。cookie的名称必须是经过URL编码的。
  2. 值(cookie-value):储存在cookie中的字符串值。值必须被URL编码。
  3. 域(Domain=<domain-value>):可选,指定cookie可以送达的主机名。假如没有指定,那么默认值为当前文档访问地址中的主机部分(但是不包含子域名)。与之前的规范不同的是,域名之前的点号会被忽略。假如指定了域名,那么相当于各个子域名也包含在内了。
  4. 路径(Path=<path-value>):可选,指定一个URL路径,这个路径必须出现在要请求的资源的路径中才可以发送cookie首部。
  5. 失效时间(Expires=<date>):可选,表示cookie何时应该别删除的时间戳。默认情况下,浏览器会话结束时即将所有的cookie删除;不过也可以自己设置删除时间。这个值是个GMT格式的日期(Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于知道个应该删除cookie的准确时间。因此,cookie可在浏览器关闭后依然保存在用户的机器上。如果设置的失效时间是个以前的时间,则cookie会被立即删除。
  6. Max-Age=<none-zone-digit>:可选,在cookie失效之前需要经过的秒数。秒数为0或-1将会使cookie直接过期。一些老的浏览器(ie6、ie7、ie8)不支持这个属性。对于其他浏览器来说。假如二者(指Expire是和Max-Age)均存在,那么Max-Age优先级跟高。
  7. 安全标志(Secure):可选,一个带有安全属性的cookie只有在请求使用SSL和HTTPS协议的时候才会被发送到服务器。然而保密或者敏感信息永远不要在HTTP cookie中存储或运输,因为整个机制从本质上来说都是不安全的,比如前述协议并不意味着所有的信息都是经过加密的。
  8. HttpOnly:可选,设置了HttpOnly属性的cookie不能使用JavaScript经由Document.cookie属性、XMLHttpRequest和RequestAPIs进行访问,以防范跨站脚本攻击(XSS)。

创建Cookie

当服务器收到HTTP请求时,服务器可以在响应头里面添加一个Set-Cookie选项。浏览器收到响应后通常会保存下Cookie,之后对该服务器的每一次请求中都通过Cookie请求头部将Cookie信息发送给服务器。另外,Cookie的过期时间、域、路径、有效期、使用站点都可以根据需要来指定。

Set-Cookie响应头部和Cookie请求头部

服务器使用Set-Cookie响应头部向用户代理(一般是浏览器)发送Cookie信息。一个简单的Cookie可能像这样:

1 Set-Cookie: <cookie名>=<cookie值>

服务器通过该头部告知客户端保存Cookie信息

1 HTTP/1.1 200 OK
2 Content-type: text/html
3 Set-Cookie: name=value
4 Other-header: other-header-value

现在,对该服务器发起的每一次请求,浏览器都会将之前保存的Cookie信息通过Cookie请求头部在发送给服务器

1 GET /index.html HTTP/1.1
2 Host: www.example.org
3 Cookie: name=value
4 Other-header: other-header-value

定义Cookie的生命周期

Cookie的生命周期可以通过两种方式定义:

  1. 会话期Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。会话期Cookie不需要指定过期时间(Expires)或者有效期(Max-Age)。需要注意的是,有些浏览器提供了会话恢复功能,这种情况下即使关闭了浏览器,会话期Cookie也会被保留下来,就好像浏览器从来没有关闭一样,这会导致Cookie的声明周期无限期延长。
  2. 持久性Cookie:持久性Cookie的生命周期取决于过期时间(Expires)或有效期(Max-Age)指定的一段时间
1 Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

限制访问Cookie

有两种方法可以确保Cookie被安全发送,并且不会被意外的参与者或脚本访问:Secure属性和HttpOnly属性。

标记为Secure的Cookie只应通过被HTTPS协议加密过的请求发送给服务端,因此可以预防man-in-the-middle攻击者的攻击。但即便设置了Secure标记,敏感信息也不应该通过Cookie传输,因为Cookie有其固有的不安全性,Secure标记也无法提供确实的安全保障。

JavaScript Document.cookie API无法访问带有HttpOnly属性的cookie;此类Cookie仅作用于服务器。例如,持久化服务器端会话的Cookie不需要对JavaScript可用,而应就有HttpOnly属性。此预防措施有助于缓解跨站点脚本(XSS)攻击。

1 Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

Cookie的作用域

Domain和Path标志定义了Cookie的作用域:即允许Cookie应该发送给那些URL。

Domain属性

Domain指定了那些主机可以接收Cookie。如果不指定,默认为origin,不包含子域名。如果指定了Domain,则一般包含子域名。因此,指定Domain比省略它的限制要少。但是,子域需要共享有关用户的信息是,这可能会有所帮助。

例如,如果设置Domain=Mozilla.org,则Cookie也包含在子域名中(如developer.mozilla.org)。

Path属性

Path标识指定了主机下的哪些路径可以接收Cookie(该URL路径必须存在于请求URL中)。以字符 %x2F("/")作为路径分隔符,子路径也会被匹配。

例如,设置Path=/docs,则以下地址都会匹配:

  • /docs
  • /docs/Web/
  • docs/Web/HTTP

SameSite attribute

SameSite Cookie 允许服务器要求某个cookie在跨站请求时不会被发送,(其中 Site 由可注册域定义),从而可以防止跨站请求伪造攻击(CSRF)。

SameSite Cookies 是相对较新的一个字段,所有主流浏览器都已经得到支持。

1 Set-Cookie: key=value; SameSite=Strict

SameSite 可以有下面三种值:

  • None:浏览器会在同站请求、跨站请求下继续发送cookies,不区分大小写。
  • Strict:浏览器只在访问相同站点时发送cookie。
  • Lax:与Strict类似,但用户从外部站点导航至URL时(例如通过链接)除外。在新版本浏览器中,为默认选项,SameSite cookies将会为一些跨站子请求保留,如图片加载或者frames的调用,但只有当用户从外部站点导航到URL时才会发送。如link链接

注:大多数主流浏览器正在将SameSite的默认值迁移这Lax。如果想要指定Cookies在同站、跨站请求都被发送,现在需要明确指定SameSite为None。

Cookie prefixes

__Host-:如果cookie名称具有此前缀,则仅当它也用Secure属性标记,是从安全来源发送的,不包括Domain属性,并将Path属性设置为/时,它才在Set-Cookie标头中接受。这样,这些cookie可以被视为"domain-locked"。

__Secure-:如果cookie名称具有此前缀,则仅当它也用Secure属性标记,是从安全来源发送的,它才在Set-Cookie标头中接受。该前缀限制要弱于__Host-前缀。

JavaScript中的cookie

在JavaScript中处理cookie有些复杂,使用BOM提供的document.cookie属性。当用来获取属性值时,document.cookie返回当前页面可用的(根据cookie的域、路径、失效时间和安全设置)所有cookie的字符串,一系列由分号隔开的名值对儿。如下所示:

1 name1=value1;name2=value2;name3=value3;

所有名字和值都是经过URL编码的,所以必须使用decodeURICompent()来解码。

当用于设置值时,document.cookie属性可以设置一个新的cookie字符串。这个cookie字符串会被解释并添加到现有的cookie集合中。设置document.cookie并不会覆盖cookie,除非设置cookie的名称已经存在。设置cookie的格式如下,和Set-Cookie头中使用的格式一样。

1 name=value;expires=expiration_time;path=domain_path;domain=domain_name;secure

这些参数中,只有cookie的名字和值时必需的。

1 document.cookie = "name=Jack";

通过JavaScript创建的Cookie中不能包含HttpOnly标志。

安全

缓解涉及Cookie的攻击的方法:

  • 使用HttpOnly属性可防止通过JavaScript访问cookie值
  • 用于敏感信息(例如指示身份验证)的Cookie的生存期应较短,并且SameSite属性设置为Strict或Lax。在支持SameSite的浏览器中这样做的作用是确保不与跨站请求一起发送身份验证cookie,因此,这种请求实际上不会向应用服务器进行身份验证。

 

posted @ 2019-09-22 20:02  焱雨  阅读(409)  评论(0编辑  收藏  举报