关于Cookie的知识的总结

Cookie的类型

会话cookie和持久cookie

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

持久cookie的生存时间更长一些,它存储在用户的硬盘上,浏览器退出或计算机重启时他们仍然存在。

会话cookie与持久cookie之间的唯一区别就是它们的过期时间。

如果设置了Discard参数(cookie版本1中的参数),或者没有设置Expires或者Max-Age参数(cookie版本1中的参数)来说明扩展的过期时间,这个cookie就是一个会话cookie。

Cookie是如何工作的

Cookie可以通过服务器进行设置,相当于服务器给用户贴的一个标签,用于跟踪用户的状态。

通过服务器设置的cookie信息通过响应头返回给浏览器,浏览器将响应头中的cookie信息保存在本地,当下次向服务器发送HTTP请求时,就自动将保存的这些cookie信息添加到请求头中(包含通过document.cookie接口设置的cookie)。

下面是退出博客园登录时的响应头和请求头,响应头中有Set-Cookie字段,请求头中有Cookie字段:

通过BOM提供的document.cookie接口,在前端可以对cookie进行操作(增、删、改),本质上是对符合一定规律的一个字符串进行操作,这样开发人员就可以利用cookie在本地存储一些数据。当然,建议存储一些非敏感信息。

Cookie的限制和组成

Cookie的限制

Cookie的限制主要有两条:

  1. 访问cookie时的同源限制
  2. Cookie的个数和尺寸限制

同源限制

Cookie在性质上是绑定在特定的域名下的。当创建了一个cookie后,再给创建它的域名发送请求时,请求头中都会包含这个cookie。这个限制确保了储存在cookie中的信息只能让批准的域访问,而无法被其他域访问。

个数和尺寸限制

每个域名下可绑定的cookie的个数是有限的,不同浏览器所限制的个数不同。

浏览器对同域名下cookie个数的限制见下表:

浏览器

可绑定的cookie的个数

IE6

20

IE7

50

Firefox

50

Opera

30

Safari

没有硬性限制

Chrome

没有硬性限制

当超过单个域名限制之后还要再设置cookie,浏览器就会清除以前设置的cookie。

浏览器中对于单个cookie的尺寸也有限制,一般限制在4KB。尺寸限制影响到一个域名下的所有cookie,而并非每个cookie单独限制。

Cookie的组成

名称和值 name = value:必填。name和value都是字符序列,除非包含在双引号内,否则不包括分号、逗号、等号和空格。Web服务器可以创建任意的name=value关联,浏览器在后继对站点的访问中会将其送会给web服务器。

域  domain:可选。表示该cookie对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域(如www.wrox.com,表示该cookie信息只向该域名发送),也可以不包含(如.wrox.com,则对于wrox.com的所有子域都有效)。如果没有明确规定,那么这个域会被认作来自设置该cookie的那个服务器所在的域。

路径  path:可选。通过这个字段可以为服务器上特定的文档分配cookie。如果path字段是一个URL路径前缀,就可以附加一个cookie。例如:路径 /foo与 /foobar和 /foo/bar.html相匹配。路径 / 与域名中的所有内容都匹配。默认值是设置 Cookie 时的当前目录。

失效时间  expires(新版的cookie规范中是max-age字段):可选。这个字段会指定一个日期字符串,用来定义cookie的实际生存期。一旦到了这个日期,就不再存储或发布这个cookie了,该cookie就会被删除。如果设置的日期是以前的时间,则cookie会被立刻删除。

日期格式为GMT格式:Wdy, DD-Mon-YYYY HH:MM:SS GMT。

安全标志  secure:可选。该字段不是键值对的形式,如果要指定该字段,只要在设置cookie时添加secure字符即可。设置了该字段后,该cookie只有在使用SSL连接的时候才发送到服务器。例如:指定域为www.wrox.com的cookie,在制定了secure字段后,该cookie只能发送给https://www.wrox.com,而发送给http://www.wrox.com的请求不会添加该cookie。

HTTP专用  HttpOnly:可选。该字段只能在服务端设置,表示该cookie是否能通过JS(BOM的document.cookie接口)去访问。默认情况下HttpOnly字段为空,表示可以通过JS访问该cookie。

按照规范,开发人员无法利用JS在前端修改cookie的HttpOnly字段,不过有的浏览器没有这个限制,具体看这篇文章:浏览器中因cookie设置HttpOnly标志引起的安全问题

关于如何在服务端设置该字段,请看这篇文章:关于Cookie安全性设置的那些事

注意:域、路径、失效时间、安全标志(secure)和HttpOnly字段都是服务器给浏览器的指示,告诉浏览器如何存储和发送cookie,这些参数并不会作为发送到服务器的cookie信息的一部分,只有cookie中的名值对儿(name=value)才会被发送。

在前面的图片中,响应头中的一个Set-Cookie就代表一个cookie;请求头中的Cookie字段中可以包含多个cookie的名值对儿,而不是仅包含一个cookie的名值对儿。

BOM的document.cookie接口

当用来获取cookie时,document.cookie返回当前页面可用的所有cookie的字符串,一系列由分号隔开的名值对儿。

例如,我在Chrome中打开这个页面:https://segmentfault.com/a/1190000004556040,在控制台中输入以下代码:

console.log(document.cookie);

控制台中会输出以下结果:

PHPSESSID=web2~f57e474e4a8mc396h4du05qsa0;
Hm_lvt_e23800c454aa573c0ccb16b52665ac26=1495500966;
Hm_lpvt_e23800c454aa573c0ccb16b52665ac26=1495500966;
_ga=GA1.2.1399344530.1495500966;
_gid=GA1.2.584865054.1495500966;
showRegister2=true;
showRegister=false

有七个由分号分隔得名值对儿,表示有七个cookie可用(所有名字和值都是经过URL编码的,所以必须使用decodeURIComponent()来解码。)。

点击开发者工具中的Application选项,在左边找到Cookies下拉菜单,点击第一个域名,就可以看到这七个cookie的详细信息。具体如下:

当用于设置cookie时,document.cookie可以设置一个新的cookie字符串,这个cookie字符串会被解释并添加到当前现有的cookie集合中。其中名值对儿(name=value)是必须的(最好用encodeURIComponent()对name和value进行编码),其它字段在cookie的组成部分已做过介绍。

通过document.cookie设置的cookie并不会覆盖现有的cookie,除非设置的cookie的name在现有cookie集合中已经存在,并且path/domain/secure这几个选项一定要和旧cookie 保持一样。否则不会修改旧cookie,而是添加了一个新的 cookie。

例子(使用wamp环境):

PHP代码:

<?php setcookie("abc", "test",null, '/' );   ?>

HTML代码:

<button id="btn" type="button" value="submit">发送请求</button>
<button id="display-cookie" type="button" value="submit">显示cookie</button>
<button id="reset-cookie" type="button" value="submit">设置cookie</button>

JS代码:

function myAJAX(url) {
    var xhr  = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if(xhr.readyState === 4) {
            if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
                console.log(xhr.responseText);
                console.log(xhr.responseXML);
            } else {
                console.log(xhr.statusText);
                console.log(xhr.status);
            }
        }
    };
    xhr.open("get",url,true);//true表示异步,false表示同步
    //此处设置头部信息

    xhr.send(null);
}
function init(){
    var btn = document.getElementById('btn');
    var displayCookie = document.getElementById('display-cookie');
    var resetCookie = document.getElementById('reset-cookie');
    var removeCookie = document.getElementById('remove-cookie');
    btn.addEventListener('click',function(event) {
        var url = 'cookie.php';
        myAJAX(url);
    },false);
    
    displayCookie.addEventListener('click',function(event) {
        console.log(document.cookie);
    },false);

    resetCookie.addEventListener('click',function(event) {
        document.cookie = "abc=ok;path=/"
    },false);
}
init();

 第一次打开该页面时,点击显示cookie按钮,控制台无输出内容,谷歌开发者工具中Application选项卡中的cookie选项中也为空。

点击发送请求按钮,在Network选项卡中查看头部信息:

在Application选项卡中的cookies选项查看cookie:

 现在点击显示cookie按钮:

只显示出了名值对儿,没有显示该cookie的其它字段的信息。

接下来点击设置cookie按钮,重设该cookie,然后再点击显示cookie按钮:

该cookie的值被重设为了ok。

我们再点击发送请求按钮,看看这一次请求的头部信息:

请求头中的Cookie字段是浏览器发送给服务器的cookie信息,cookie的值之前被我们设置为了ok。响应头中的Set-Cookie字段是服务器返回给浏览器的cookie信息(实际上这时,cookie的值又被设置为了test)(我只是描述这个现象,不知道理解的对不对。)。

没有删除已有cookie的直接方法。所以,需要使用相同的路径(path)、域(domain)和安全选项(secure)再次设置原cookie,并将失效时间设置为过去时间

 

通过document.cookie设置的cookie也会被浏览器添加到请求头中。

举例,用document.cookie设置cookie:

document.cookie = encodeURIComponent(“username”) + “=” +
encodeURIComponent(“jack”) + “; domain=.wrox.com; path=/”;

子cookie

子cookie是存放在单个cookie中的更小段的数据。也就是使用cookie值来存储多个名值对儿。

一种子cookie的格式:

name=name1=value1&name2=value2&name3=value3&name4=value4

本质上还是字符串的操作。

CORS中的cookie

(摘自阮一峰老师的文章:跨域资源共享 CORS 详解

CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段为true。另一方面,开发者必须在AJAX请求中打开XMLHttpRequest对象的withCredentials属性。否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。

但是,如果省略withCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭withCredentials。

需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

 

写在后面的话:

上面关于cookie的总结,仅仅是我了解到的关于cookie的知识。

关于cookie的规范:

https://tools.ietf.org/html/rfc6265

参考文章:

1、聊一聊 cookie

2、http://php.net/manual/zh/function.setcookie.php

3、HTTP权威指南第11章

4、Javascript高级程序设计(第三版)第23章

相关文章:

1、漫谈Cookie安全

2、Cookie/Session机制详解

3、Document.cookie MDN

posted @ 2017-05-24 12:45  Fogwind  阅读(1469)  评论(0编辑  收藏  举报