一文了解cookie

@

什么是Cookie?

Cookie 就是访问者在访问网站后留下的一个信息片段。它存储在客户端(通常来说是浏览器)。你可以把cookie当作一个map,里边是键值对,每个键值对有过期时间、域、路径、脚本可否访问等描述信息;描述信息存储在客户端,客户端请求时,默认会带上cookie的名称和值,不会带描述信息,通过http请求报文header中的cookie项进行传输;服务器响应时,可以设置cookie信息,就在http响应报文的header中Set-Cookie项。

那么,它究竟有什么作用呢?

众所周知,HTTP 协议是无状态的协议,如果你在同一个客户端向服务器发送多次请求,服务器不会知道这些请求来自同一客户端(同一个用户)。

这样有什么好处呢?如果它是有状态协议,你必须要时刻与服务器建立链接,那么如果连接意外断开,整个会话就会丢失,重新连接之后一般需要从头开始;而如果是无状态协议,使得会话与连接本身独立起来,这样即使连接断开了,会话状态也不会受到严重伤害,保持会话也不需要保持连接本身。

但是,缺点也很明显:即使同一个客户端连续两次发送请求给服务器,服务器也识别不出这是同一个客户端发送的请求,这导致的问题就比如你加了一个商品到购物车中,但因为识别不出是同一个客户端,你刷新下页面就没有了。

为了使服务器知道每个请求具体来自于哪个用户,比如你在逛淘宝的时候你只需要登录一次,当你发起一次购买请求,服务器就已经知道你登录过了,不会再让你进行登录。

由此,Cookie诞生了,Cookie就是一种浏览器管理状态的一个文件,让无状态的 HTTP 协议拥有一小块记忆。

HTTP Cookie 机制是 HTTP 协议无状态的一种补充和改良

Cookie 主要有以下用途:

  • 会话管理:登陆、购物车等应该记住的其他内容
  • 个性化:用户偏好、主题或者其他设置

  • 追踪:记录和分析用户行为

Cookie原理

第一次访问网站的时候,浏览器发出请求,服务器响应请求后,会将cookie放入到响应请求中(就在http响应报文的header中Set-Cookie项),在浏览器第二次发请求的时候,会把cookie带过去(http请求报文header中的cookie项),服务端会辨别用户身份,当然服务器也可以修改cookie内容。

Set-Cookie 和 Cookie 标头

Set-Cookie HTTP 响应标头将 cookie 从服务器发送到用户代理。下面是一个发送 Cookie 的例子

![在这里插入图片描述]( https://img-blog.csdnimg.cn/798e745455104fa8b997d05e38860772.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aSP5a6J44CA44CA44CA,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

随着对服务器的每个新请求,浏览器将使用 Cookie 头将所有以前存储的 Cookie 发送回服务器。

![在这里插入图片描述]( https://img-blog.csdnimg.cn/4d09450874534275aef45ee7385d3954.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aSP5a6J44CA44CA44CA,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

Cookie的分类

有两种类型的 Cookies,一种是 Session Cookies,一种是 Persistent Cookies,如果 Cookie 不包含到期日期,则将其视为会话 Cookie。会话 Cookie 存储在内存中,永远不会写入磁盘,当浏览器关闭时,此后 Cookie 将永久丢失。如果 Cookie 包含有效期 ,则将其视为持久性 Cookie。在到期指定的日期,Cookie 将从磁盘中删除。还有一种是 Cookie的 Secure 和 HttpOnly 标记,后面会介绍。

会话 Cookies

会话 Cookie 有个特征,客户端关闭时 Cookie 会删除,因为它没有指定Expires或 Max-Age 指令。

但是,Web 浏览器可能会使用会话还原,这会使大多数会话 Cookie 保持永久状态,就像从未关闭过浏览器一样。

例如:

![在这里插入图片描述]( https://img-blog.csdnimg.cn/84779c6d91c948fc9852c8a586f1b604.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aSP5a6J44CA44CA44CA,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

永久性 Cookies

永久性 Cookie 不会在客户端关闭时过期,而是在特定日期(Expires)或特定时间长度(Max-Age)外过期。例如:

![在这里插入图片描述]( https://img-blog.csdnimg.cn/17c87b0d90564e7996d9fcb5fdbcf2a7.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aSP5a6J44CA44CA44CA,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

name

cookie的名字,一个域名下绑定的cookie,name不能相同,相同的name的值会被覆盖掉

value

value表示cookie的值

【注】用 JavaScript 操作 Cookie 的时候注意对 value 进行编码处理。

Domain

这个代表的是,cookie绑定的域名,如果没有设置,就会自动绑定到执行语句的当前域。由于同源策略,脚本只能访问父域名或本域名的cookie(浏览器只能发送父域名或本域名的cookie),比如设置cookie域名为一级域名mydomain.com;那么此域名下的二级域名www.mydomain.com,images.mydomain.com页面,都可以访问此cookie

【注】cookie区分域,而不区分端口,也就是说,同一个ip下的多个端口下的cookie是共享的!更确切的说,请求是会带上同域下所有端口的cookie,但是返回时会覆盖。

例如以下栗子:

![在这里插入图片描述]( https://img-blog.csdnimg.cn/066a8f7ef9dd45e5a4ac667436cb9b25.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aSP5a6J44CA44CA44CA,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
![在这里插入图片描述]( https://img-blog.csdnimg.cn/55150fc5a9e947428f94b60dcc53aa0d.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aSP5a6J44CA44CA44CA,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

Path

Path这个属性默认是'/',这个值匹配的是web的路由

cookie是区分路径的,也就是说,同一个键值对可以同时设置到 www.mydomain.com,www.mydomain.com/b下,并且是独立的,互不影响的;如果不指定路径,默认是当前路径。

Domain 和 Path 标识共同定义了 Cookie 的作用域:即 Cookie 应该发送给哪些 URL。

Expires

Expires 用于设置 Cookie 的过期时间。当 Expires 属性缺失时,表示是会话性 Cookie,值保存在客户端内存中,并在用户关闭浏览器时失效。需要注意的是,有些浏览器提供了会话恢复功能,这种情况下即使关闭了浏览器,会话期 Cookie 也会被保留下来,就好像浏览器从来没有关闭一样。

与会话性 Cookie 相对的是持久性 Cookie,持久性 Cookies 会保存在用户的硬盘中,直至过期或者清除 Cookie。这里值得注意的是,设定的日期和时间只与客户端相关,而不是服务端。

所以如果你想要cookie存在一段时间,那么你可以通过设置Expires属性为未来的一个时间节点,Expires这个是代表当前时间的,然而这个属性已经逐渐被Max-Age代替。

Max-Age

Max-Age 用于设置在 Cookie 失效之前需要经过的秒数。

Max-Age可以为正数、负数、甚至是 0。

  • 当 Max-Age 属性为正数时,浏览器会将其持久化,即写到对应的 Cookie 文件中。

  • 当 Max-Age 属性为负数,则表示该 Cookie 只是一个会话性 Cookie。

  • 当 Max-Age 为 0 时,则会立即删除这个 Cookie。因为cookie机制本身没有设置删除cookie,失效的cookie会被浏览器自动从内存中删除,所以,它实现的就是让cookie失效。

【注】假如 Expires 和 Max-Age 都存在,Max-Age 优先级更高。

Secure

由于http不仅是无状态的,还是不安全的协议,容易被劫持。所以标记为 Secure 的 Cookie 只应通过被https协议加密过的请求发送给服务端。使用 https 安全协议,可以保护 Cookie 在浏览器和 Web 服务器间的传输过程中不被窃取和篡改。

HTTPOnly

如果这个属性设置为true,就不能通过js脚本来获取cookie的值,能有效的防止xss攻击。

SameSite

Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击和用户追踪。

Cookie 的SameSite属性可以设置三个值:

  • Strict
  • Lax
  • None

Strict

Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。

这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。

Lax

Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。

导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。

请求类型 示例 正常情况 Lax
链接 <a href="..."></a> 发送 Cookie 发送 Cookie
预加载 <link rel="prerender" href="..."/> 发送 Cookie 发送 Cookie
GET 表单 <form method="GET" action="..."> 发送 Cookie 发送 Cookie
POST 表单 <form method="POST" action="..."> 发送 Cookie 不发送
iframe <iframe src="..."></iframe> 发送 Cookie 不发送
AJAX $.get("...") 发送 Cookie 不发送
Image <img src="..."> 发送 Cookie 不发送

设置了Strict或Lax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。

None

Chrome 已将Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 https 协议发送),否则无效。

Cookie的读写

document.cookie属性用于读写当前网页的 Cookie。

读取的时候,它会返回当前网页的所有 Cookie,前提是该 Cookie 不能有HTTPOnly属性。

document.cookie // "foo=bar;baz=bar"

document.cookie属性是可写的,可以通过它为当前网站添加 Cookie。
写入的时候,Cookie 的值必须写成key=value的形式。注意,等号两边不能有空格。另外,写入 Cookie 的时候,必须对分号、逗号和空格进行转义(它们都不允许作为 Cookie 的值),这可以用encodeURIComponent方法达到。
但是,document.cookie一次只能写入一个 Cookie,而且写入并不是覆盖,而是添加。

document.cookie = 'test1=hello';
document.cookie = 'test2=world';
document.cookie
// test1=hello;test2=world

document.cookie读写行为的差异(一次可以读出全部 Cookie,但是只能写入一个 Cookie),与 HTTP 协议的 Cookie 通信格式有关。浏览器向服务器发送 Cookie 的时候,Cookie字段是使用一行将所有 Cookie 全部发送;服务器向浏览器设置 Cookie 的时候,Set-Cookie字段是一行设置一个 Cookie。

写入 Cookie 的时候,可以一起写入 Cookie 的属性。

document.cookie = "test=hello; expires=Fri, 31 Dec 2020 23:59:59 GMT";

上面代码中,写入 Cookie 的时候,同时设置了expires属性。属性值的等号两边,也是不能有空格的。

各个属性的写入注意点如下。

  • path属性必须为绝对路径,默认为当前路径。
  • domain属性值必须是当前发送 Cookie 的域名的一部分。比如,当前域名是example.com,就不能将其设为foo.com。该属性默认为当前的一级域名(不含二级域名)。
  • max-age属性的值为秒数。
  • expires属性的值为 UTC 格式,可以使用Date.prototype.toUTCString()进行日期格式转换。

document.cookie写入 Cookie 的例子如下。

document.cookie = 'fontSize=14; '
  + 'expires=' + someDate.toGMTString() + '; '
  + 'path=/subdirectory; '
  + 'domain=*.example.com';

Cookie 的属性一旦设置完成,就没有办法读取这些属性的值。

删除一个现存 Cookie 的唯一方法,是设置它的expires属性为一个过去的日期。或者上面提到的Max-Age属性。

document.cookie = 'fontSize=;expires=Thu, 01-Jan-1970 00:00:01 GMT';

上面代码中,名为fontSize的 Cookie 的值为空,过期时间设为1970年1月1月零点,就等同于删除了这个 Cookie。
参考:

posted @ 2021-11-10 11:37  clienter  阅读(1094)  评论(0)    收藏  举报