一格维述 - 一文了解cookie

什么是Cookie?

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

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 的例子
    随着对服务器的每个新请求,浏览器将使用 Cookie 头将所有以前存储的 Cookie 发送回服务器。

    Cookie的分类

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

    会话 Cookies

    会话 Cookie 有个特征,客户端关闭时 Cookie 会删除,因为它没有指定Expires或 Max-Age 指令。
    但是,Web 浏览器可能会使用会话还原,这会使大多数会话 Cookie 保持永久状态,就像从未关闭过浏览器一样。
    例如:

    永久性 Cookies

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

    Cookie 的属性

    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,但是返回时会覆盖。
    例如以下例子:

    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
链接
发送 Cookie 发送 Cookie
预加载
发送 Cookie 发送 Cookie
GET 表单
发送 Cookie 发送 Cookie
POST 表单
发送 Cookie 不发送
iframe
发送 Cookie 不发送
AJAX $.get(“…”) 发送 Cookie 不发送
Image
发送 Cookie 不发送

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

None

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

参考