基础知识
cookie从哪来到哪去
从哪来
浏览器添加cookie的时机:
有客户端来设置:通过javascript的api——document.cookie来操作
设置
1document.cookie = 'name=value; maxAge=3000; path=/; domain=xx.com; secure'cookie的名和值中不能出现分号、逗号、等号和空格,每一个key之间通过分号和空格来分割。
设置多个cookie
通过document.cookie的方式来设置cookie每次只能设置一个cookie。如果我们写多个会有什么效果呢?
1document.cookie = 'cookie1=value1; cookie2=value2'
放在console中运行一下,会发现,只有第一个cookie1设置成功,而cookie2被无视了。所以要设置多个cookie,最简单的方式就是多次调用document.cookie。
由服务端来设置:http的响应头中。
打开浏览器的控制台,在network下我们可以看到浏览器发出的所有请求。这些请求的返回头中,有些会发现一个Set-Cookie的字段。
服务器通过这个字段来告诉浏览器,它需要设置一个cookie,然后浏览器检查一下要设置的内容是否满足浏览器定下的cookie的“条条框框”,如果满足那么一个cookie就诞生了。这里提到了“条条框框”我们稍后做解答。在上图中,响应头里set-cookie字段可以有多个,每一个对应一个要设置的cookie,且只能对应一个。
到哪去
客户端主动获取
和客户端设置相同,获取的时候也是通过document.cookie来读取:
1var cookies = document.cookie读取到的cookie为一串字符串,每个cookie之间通过分号来分割。
随着请求发送
浏览器发送请求时,在请求的头中会自动将“符合条件”的cookie带上。
既然是请求头中携带的,那么我们通过ajax发送请求的时候,能否顺便设置一下cookie呢?简单的实验一下即可知晓:12345var 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。也就说以下写法是不会生效的:
1document.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-attribute和goodbye-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/