基础知识

cookie从哪来到哪去

从哪来

浏览器添加cookie的时机:

  • 有客户端来设置:通过javascript的api——document.cookie来操作

    设置
    1
    document.cookie = 'name=value; maxAge=3000; path=/; domain=xx.com; secure'

    cookie的名和值中不能出现分号、逗号、等号和空格,每一个key之间通过分号和空格来分割。

    设置多个cookie

    通过document.cookie的方式来设置cookie每次只能设置一个cookie。如果我们写多个会有什么效果呢?

    1
    document.cookie = 'cookie1=value1; cookie2=value2'
放在console中运行一下,会发现,只有第一个cookie1设置成功,而cookie2被无视了。所以要设置多个cookie,最简单的方式就是多次调用document.cookie。
  • 由服务端来设置:http的响应头中。

    打开浏览器的控制台,在network下我们可以看到浏览器发出的所有请求。这些请求的返回头中,有些会发现一个Set-Cookie的字段。
    set-cookie
    服务器通过这个字段来告诉浏览器,它需要设置一个cookie,然后浏览器检查一下要设置的内容是否满足浏览器定下的cookie的“条条框框”,如果满足那么一个cookie就诞生了。这里提到了“条条框框”我们稍后做解答。

    在上图中,响应头里set-cookie字段可以有多个,每一个对应一个要设置的cookie,且只能对应一个。

到哪去

  • 客户端主动获取

    和客户端设置相同,获取的时候也是通过document.cookie来读取:

    1
    var cookies = document.cookie

    读取到的cookie为一串字符串,每个cookie之间通过分号来分割。

  • 随着请求发送

    浏览器发送请求时,在请求的头中会自动将“符合条件”的cookie带上。
    既然是请求头中携带的,那么我们通过ajax发送请求的时候,能否顺便设置一下cookie呢?简单的实验一下即可知晓:

    1
    2
    3
    4
    5
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.withCredentials = true;
    xhr.setRequestHeader('Cookie', "key=value");
    xhr.send(null);

    然后我们看看实际上浏览器发送出去的请求:

    我们设置的cookie并没有生效,并且chrome浏览器下我们会看到一行报错

    Refused to set unsafe header “Cookie”

    所以说,因为浏览器的安全限制,我们不能自己随便设置请求头中的cookie。

cookies条条框框

一个cookie除了value外,还有domain、path、expires/max-age、httpOnly、secure、sameSite这些属性。设置cookie的时候,可以对这些相关属性进行设置,当然也可以不进行设置,这时浏览器会自动给这些属性一个默认值。cookie的条条框框就和这些属性脱不了干系。

  • domain

    domain限制了cookie的使用范围:只能在domain值的范围中才能访问到该cookie.

    同时domain值的设置也有严格的要求。

    • 自身

      毫无疑问domain的值可以设置为本身。

    • 向下:所有子域名

      如果我们当前页面的域名是 sub.test.com, 那么 domain 可以设置为.sub.test.com。允许所有sub.test.com的子域名访问,如xx.sub.test.com、xx.xx.sub.test.com。

    • 向上:父级域名,直到Top-Level的下一级

      如果我们当前页面的域名是sub.test.com, 那么domain可以设置为test.com。但是不能设置为.com。因为.com属于Top-Level Domain

  • path

    domain+path 共同限制了可访问该cookie的URL。如果某个cookie的path=’/home’,那么只有“domain/home”下的所有url可以访问该cookie。

  • expires/max-age

    这两个值决定了cookie能活多久。如果不进行设置,那么浏览器会默认将cookie的有效期设置为 session,当页面关闭后cookie便随之被清理了。如果希望cookie在页面关闭后,仍然能保存一段时间,那么就需要为cookie设置一个过期时间,在过期时间内浏览器都会为我们保留该cookie.

    expires 是 http/1.0协议中的选项,在新的http/1.1协议中expires已经由 max-age 选项代替。expires必须是 GMT 格式的时间。

    max-age的单位为秒,cookie失效时刻 = 创建时刻 + max-age

  • httpOnly

    如果一个cookie被标记为httpOnly, 那么前文所提到的通过document.cookie的方式就无法获取到该cookie。同样的,我们通过js来设置cookie的,也无法被标记为httpOnly。也就说以下写法是不会生效的:

    1
    document.cookie="cookie1=value1; HttpOnly"

    这个值只能通过请求的响应头来设置。默认情况下,cookie不会带httpOnly选项。

  • Secure

    对于被标记为Secure的cookie,只有当请求是HTTPS或者其他安全协议时,该cookie 才能被访问到。同样的,也只有在HTTPS或者其他安全协议时,我们也才能通过js设置secure的cookie。

  • sameSite

    这个值这是谷歌开发的一种安全机制,用来定义cookie如何跨域发送,其目的是尝试阻止CSRF。chrome51版本已经支持。关于各大浏览器的支持情况,参考chrome官网。关于这个特性,这里不多做介绍了,感兴趣的可参看preventing-csrf-with-samesite-cookie-attributegoodbye-csrf-samesite-to-the-rescue

    最后,这些所有的属性值,一起决定了一件事——这个cookie那个URL可以能用。

参考文献:
https://developers.livechatinc.com/blog/setting-cookies-to-subdomains-in-javascript/
https://www.sjoerdlangkemper.nl/2016/04/14/preventing-csrf-with-samesite-cookie-attribute/

阅读全部