Cookie 是服务器发送给浏览器,由浏览器保存在本地的一些数据,在浏览器向目标服务器再次发起请求时,浏览器会携带Cookie domain与目标服务器domain相同或Cookie domain为目标服务器的父域名的cookie。
Cookie存在的意义要从HTTP协议说起,HTTP协议是一个无状态协议。无状态的含义就是客户端的每个请求对服务器来说都是全新的,即使客户端在前一秒发送请求告诉服务器我是userA,下一秒再发送请求时,服务器会响应,但是它不知道当前请求还是来自userA的。每个请求都是独立的,上一个请求和下一个请求之间是没有任何联系的。
HTTP协议设计为无状态的,主要是因为服务器需要面向全世界数十万、上百万的用户,而每个客户端(即浏览器)与服务器之间交换数据的间歇性较大(即传输具有突发性、瞬时性),并且网页浏览的联想性、发散性导致两次传送的数据关联性很低,大部分连接实际上会很空闲、无端占用资源。因此 HTTP 的设计者针对用户访问服务器的这些特点将协议设计为发起请求时建立连接、请求结束时释放连接,以尽快将资源释放出来服务其他客户端。
HTTP协议的无状态就带来了一些问题,比如我们通过用户名密码登录了网站,后续再次发请求给服务器时,服务器并没有办法识别到我们在上一个请求中提供的用户信息,除非我们在请求中再次携带用户信息。如果服务器想要识别客户端的身份,那就需要通过一些方法将客户端的身份信息记录下来。目前,有两种解决方案,那就是Cookie和Session。
Cookie是通过客户端保存状态信息的解决方案。从定义上来说,Cookie就是由服务器发给客户端的特殊信息,这些信息中会包含客户端的身份信息,客户端在收到这些信息后会以文本文件的方式保存在客户端,之后客户端每次向服务器发送请求的时候都会在Cookie Header中带上这些信息。服务器在接收到来自客户端浏览器的请求之后,就能够通过分析Cookie Header中的信息得到客户端的身份信息。像很多网站的登录界面中的“请记住我”的功能就是通过Cookie实现的。
Session是通过服务器保存状态信息的解决方案。当客户端访问服务器时,服务器会创建Session并保存在服务器上,同时将标识 Session 的 SessionId 返回给客户端浏览器,浏览器将这个 SessionId 保存起来,当客户端再次发送请求的时候,会将这个SessionId带上,服务器接受到请求之后就会依据SessionId找到相应的Session,从而获取到用户信息。这里SessionId在客户端的保存方式有多种,Cookie,Local Storage, Session Storage,页面隐藏表单等都可以。但还是用Cookie比较方便,不需要额外的处理,在发送请求的时候可以自动携带。所以归根结底,服务器想要获取状态信息都离不开Cookie。
Cookie 主要用于以下三个方面:
Cookie 最主要的作用就是对请求和响应的状态进行管理, 服务端通过在响应体中设置 Cookie (状态), 客户端会将 Cookie (状态) 存储起来, 之后客户端给向该服务器发起的每个请求,浏览器都会自动将 Cookie (状态)带上, 这样服务端就能够对客户端的身份进行识别。

Set-Cookie Response Header:服务器端用于给客户端设置Cookie
- HTTP/2.0 200 OK
- Content-Type: text/html
- Set-Cookie: yummy_cookie=choco
- Set-Cookie: tasty_cookie=strawberry
Cookie Request Header:客户端用于向服务器端发送Cookie,服务器端设置Cookie之后,在Cookie过期之前,客户端发送给服务器端的每个请求都会自动带上这些Cookie。
- GET /sample_page.html HTTP/2.0
- Host: www.example.org
- Cookie: yummy_cookie=choco; tasty_cookie=strawberry
- Set-Cookie: <cookie-name>=<cookie-value>
- Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
- Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<number>
- Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
- Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
- Set-Cookie: <cookie-name>=<cookie-value>; Secure
- Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly
-
- Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Strict
- Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax
- Set-Cookie: <cookie-name>=<cookie-value>; SameSite=None; Secure
-
- // Multiple attributes are also possible, for example:
- Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly
Cookie的生命周期有两种: 第一种是会话cookie 第二种是 持久cookie
Max-Age属性设置以秒为单位的存活时间,那么浏览器就会将将这个Cookie保存在客户端的硬盘上,在过期时间之前,再次访问同一个网站的时候,会将信息通过请求头Cookie发送给服务器。Max-Age以秒为单位,设置多长时间之后过期- Set-Cookie: id=a3fWa; Expires=Thu, 31 Oct 2021 07:28:00 GMT;
- Set-Cookie: id=a3fWa; Max-Age=3600
为避免跨域脚本 (XSS) 攻击,通过 JavaScript 的 Document.cookie API 无法访问带有 HttpOnly 标记的 Cookie,它们只应该发送给服务端。
如果包含服务端 Session 信息的 Cookie 不想被客户端 JavaScript 脚本调用,那么就应该为其设置 HttpOnly 标记。
Secure标记为 Secure 的 Cookie 只应通过被 HTTPS 协议加密过的请求发送给服务端,如果使用HTTP请求(localhost除外),则Cookie不会发送给服务器。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly Domain 标识指定了浏览器在向哪些服务器发送请求时可以携带该 Cookie。如果不指定,默认为与当前页面的domain相同的服务器(不包含子域名)。如果指定了 Domain,则浏览器在给指定的Domain以及其子域名发送请求时都会携带该Cookie。
例如设置了 Domain=mozilla.org,则 浏览器在给mozilla.org或者developer.mozilla.org发送请求时都会携带该Cookie。
Set-Cookie: id=a3fWa; Domain=mozilla.org
Path 标识指定了给服务器的哪些URL 路径发送请求时会携带该 Cookie。以字符 %x2F (/) 作为路径分隔符,子路径也会被匹配。
设置 Path=/docs,则以下地址都会匹配:
/docs/docs/Web//docs/Web/HTTP以下路径不会被匹配
//docsets/fr/docsSet-Cookie: id=a3fWa; Path=/docs
首先来理解一下SameSite的含义,同源协议中的源是由「协议+域名+端口」三者一起定义的,有一个不同就不算同源,而同站只受域名的约束,并且还不要求一模一样——只要「有效顶级域名+二级域名」相同,都算同站。比如https://baidu.com,https://www.baidu.com,https://passport.baidu.com属于不同源,但是属于同站。
SameSite Cookie 允许服务器要求某个 Cookie 在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF)。
Set-Cookie: key=value; SameSite=Strict
None :浏览器会在同站请求、跨站请求下继续发送 Cookies,不区分大小写;Strict :浏览器在发送请求时只包含那些Cookie Domain与目标服务器Domian相同或是Cookie Domain是目标服务器的父Domain的CookieLax 在新版本浏览器中,为默认选项,Same-site Cookies 将会为一些跨站子请求保留,如图片加载或者 iframe 不会发送,而点击 标签会发送;
| 请求类型 | 示例 | 正常情况 | Lax |
|---|---|---|---|
| 链接 | | 发送 Cookie | 发送 Cookie |
| 预加载 | | 发送 Cookie | 发送 Cookie |
| GET 表单 | | 发送 Cookie | 发送 Cookie |
| POST 表单 | | 发送 Cookie | 不发送 |
| iframe | | 发送 Cookie | 不发送 |
| AJAX | $.get("...") | 发送 Cookie | 不发送 |
| Image | | 发送 Cookie | 不发送 |

顶级域名和二级域名相同,同站,会携带Domain为.segmentfault.com的所有Cookie,包括SameSite=None,SameSite=Strict,SameSite=Lax不会携带Domain为.sponsor.segmentfault.com的Cookie,父域名不能使用子域名的Cookie域名完全相同,同站会携带Domain为.segmentfault.com的所有Cookie,包括SameSite=None,SameSite=Strict,SameSite=Lax,子域名可以使用父域名的Cookie会携带Domain为.sponsor.segmentfault.com的所有Cookie,包括SameSite=None,SameSite=Strict,SameSite=Lax,不会携带Domain为.segmentfault.com的Cookie不会携带Domain为.sponsor.segmentfault.com的Cookie会携带Domain为.google.com且SameSite=None的CookieDomain为.google.com且SameSite=Strict的Cookie,因为请求来源的站与目标站不是同一个前面已经介绍了可以通过Domain属性设置给哪些服务器发请求时可以携带该Cookie。
如果Cookie设置了Domain属性,则给Domain指定的域及其子域发送请求时,都会携带该Cookie。比如上图中,给sponsor.segmentfault.com发请求时会携带Domain为.segmentfault.com的所有Cookie。
总结来说就是:
.segmentfault.com来说,.segmentfault.com和sponsor.segmentfault.com都属于第一方Cookie,google.com属于第三方Cookie。