Cookie全知道
Chrome更新后你还不知道Cookie中的SameSite吗?
Cookie是什么
一个Cookie就是存储在用户主机浏览器中的一小段文本文件。Cookies是纯文本形式,它们不包含任何可执行代码。一个Web页面或服务器告之浏览器来将这些信息存储。
Cookie由来
一般来说HTTP 1.x,是无状态协议,那么同一个客户端连续多次发送请求给服务器,服务器也识别不出这是同一个客户端发送的请求。为了解决这个问题才有了Cookie。在第一次访问网站的时候,服务器响应请求后,会将Cookie放入到响应请求中,在浏览器第二次发请求的时候,会把Cookie带过去,服务端会辨别用户身份。
Cookie 的设置
那 Cookie 是怎么设置的呢?简单来说就是
- 客户端发送 HTTP 请求到服务器
- 当服务器收到 HTTP 请求时,在请求返回的 Response Headers 可以看到 Set-Cookie 字段。
- 浏览器收到响应后保存下 Cookie
- 之后对该服务器每一次请求中都通过 Cookie 字段将 Cookie 信息发送给服务器。
Cookie 的属性
![](https://img.haomeiwen.com/i15259843/165ac897ae32e78f.png)
- name
代表cookie的名字一个域名下绑定的cookie,name不能相同,相同的name的值会被覆盖掉。 - value
表示cookie的值,值得注意的是用 JavaScript 操作 Cookie 的时候注意对 value 进行编码处理。
由于cookie规定是名称/值是不允许包含分号,逗号,空格的,所以为了不给用户到来麻烦,考虑服务器的兼容性,任何存储cookie的数据都应该被编码.
-
domain
这个是指的域名,这个代表的是,cookie绑定的域名,如果没有设置,就会自动绑定到执行语句的当前域,统一个域名下的二级域名也是不可以交换使用cookie的,比如设置 .test.com,这样无论是 a.test.com 还是 b.test.com 都可以公用 Cookie。 -
path
path 指定了一个 URL 路径,这个路径必须出现在要请求的资源的路径中才可以发送 Cookie 首部。path这个属性默认是'/',这个值匹配的是web的路由,举个例子:比如设置 Path=/blog,其实它会给/blog、/blogabc等等的都会带 Cookie 首部。/test 则不会携带 Cookie 。
//默认路径
www.test.com
//blog路径携带Cookie
www.test.com/blog
//不携带
www.test.com/test
-
expires
expires 用于设置 Cookie 的过期时间。一般浏览器的Cookie都是默认储存的,当关闭浏览器结束这个会话的时候,这个cookie也就会被删除是会话性 Cookie,其值保存在客户端内存中。与会话性 Cookie 相对的是持久性 Cookie,持久性 Cookies 会保存在用户的硬盘中,直至过期或者清除 Cookie。而设定的日期和时间只与客户端相关,非服务端。
举例来说:如果你想要cookie存在一段时间,那么你可以通过设置expires属性为未来的一个时间节点,expires代表当前时间。 -
Max-Age
Max-Age 用于设置在 Cookie 失效之前需要经过的秒数。比如:
Set-Cookie: id=a3fWa; Max-Age=604800;
Max-Age 可以为正数、负数、甚至是 0。
如果 max-Age 属性为正数时,浏览器会将其持久化,即写到对应的 Cookie 文件中。
- 当 max-Age 属性为负数,则表示该 Cookie 只是一个会话性 Cookie。
- 当 max-Age 为 0 时,则会立即删除这个 Cookie。
- 当 expires 和 Max-Age 都存在,Max-Age 优先级更高。
不能跨域设置 Cookie,例如:在test的域名下设置
Set-Cookie: qwerty=219ffwef9w0f; Domain=baidu.com; Path=/; Expires=Wed, 30 Aug 2020 00:00:00 GMT
是无效的,因为domain 和path共同定义了 Cookie 的作用域。
-
Secure属性
image.png
http不仅是无状态的,还是不安全的协议,容易被劫持,当Secure属性设置为true时 Cookie 只会在https和ssl等安全协议下传输,其可以保护 Cookie 在浏览器和 Web 服务器间的传输过程中不被窃取和篡改。但是个属性并不能对客户端的Cookie进行加密,还是不能保证绝对的安全性。
-
HTTPOnly
设置 HTTPOnly 属性可以防止客户端脚本通过 document.cookie 等方式访问 Cookie,有助于避免 XSS 攻击。 -
SameSite
SameSite 属性可以让 Cookie 在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF)。SameSite 有三种值:
- Strict :仅允许一方请求携带 Cookie,即浏览器将只发送相同站点请求的 Cookie,即当前网页 URL 与请求目标 URL 完全一致。
- Lax :允许部分第三方请求携带 Cookie
- None: 无论是否跨站都会发送 Cookie
之前默认是 None 的,因为 2 月份发布的 Chrome80 版本中默认屏蔽了第三方的 Cookie,其SameSite默认是 Lax。跨站和我们熟悉的跨域是不同的
js如何操作Cookie
//读取浏览器中的cookie
console.log(document.cookie);
//写入cookie
document.cookie='test=TestCookie;path=/;domain=.baidu.com';
Cookie 的作用
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
这里又引出一个问题:保存在服务器端的Session和Cookie又什么不同?又是怎么配合的的?先说几个不同:
- 有效期不同,Cookie 可设置为长时间保持,比如默认登录功能,Session 一般客户端关闭或者 Session 超时都会失效。
- 隐私策略不同,Cookie 存储在客户端;Session 存储在服务端,安全性相要好一些。
- 存储大小不同, 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie。
- 存取方式的不同,Cookie 只能保存 ASCII,Session 可以存任意数据类型比如保持一些常用变量信息,比如说 UserId 等。
Cookie 和 Session关联?
Cookie 和 Session就是来告诉服务端,本次操作用户是否登录,是哪个用户在执行的操作。
![](https://img.haomeiwen.com/i15259843/844aa4f839b55b0a.png)
用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建创建对应的 Session ,请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器,浏览器接收到后会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名。
用户第二次访问服务器的时候,请求判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。
总结一下:SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。
既然上面说了SameSite 属性可以让 Cookie 在跨站请求时不会被发送,而服务端有需要 Cookie 中的信息判断用户是否登录,那么如何保障整个机制的正常运转?
- 每次请求中携带 SessionID ,也可以 Post 的方式提交,也可以在请求的地址后面拼接 xxx?SessionID=123456...。
- Token 机制。多用于 App 客户端和服务器交互的模式,也可以用于 做用户状态管理。Token就是是“令牌”,服务端生成的一串字符串,作为客户端进行请求的一个标识。Token 机制和 Cookie 和 Session 的使用机制比较类似。
当用户第一次登录后,服务器根据提交的用户信息生成一个 Token,响应时将 Token 返回给客户端,以后客户端只需带上这个 Token 前来请求数据即可,无需再次登录验证。
如何考虑分布式 Session 问题?
为了可以支撑更大的流量,后端往往需要多台服务器共同来支撑前端用户请求,那如果用户在 A 服务器登录了,第二次请求跑到服务 B 就会出现登录失效问题。
分布式 Session 的解决一般有下面几种。
- Nginx ip_hash 策略,服务端使用 Nginx 代理,每个请求按访问 IP 的 hash 分配,这样来自同一 IP 固定访问一个后台服务器,避免了在服务器 A 创建 Session,第二次分发到服务器 B 的现象。
- Session 复制,每当在一个服务器上的 Session 发生改变(增删改操作),该节点会把这个 Session 的所有内容广播给所有其它节点,实现状态一致。
- 共享 Session,服务端无状态化,将用户的 Session 等信息使用缓存中间件来统一管理,保障分发到每一个服务器的响应结果都一致。
![](https://img.haomeiwen.com/i15259843/5e8b8a41c74dc11a.png)
举个例子可以使用redis实现分布式Session管理,客户端请求,经过Nginx负载均衡分发至tomcat实例,再经过Session管理,实现Session在redis中存取。配置redis主从集群,主redis数据热备份至从redis,当主redis宕机了,系统自动切换至从redis,从而保证系统缓存方面高可用建议这种方案。
从Cookie到Session你所需要了解的信息就都在这里了。