cookie 和 session
面试必问: session,cookie 和 token 的区别 - 云+社区 - 腾讯云
由于 http 的无状态性,为了使某个 域名 下的所有网页能够共享某些数据,session 和 cookie 出现了。客户端访问 服务器 的流程如下
- 首先,客户端会发送一个 http 请求到服务器端。
- 服务器端接受客户端请求后,建立一个 session,并发送一个 http 响应到客户端,这个响应头,其中就包含 Set-Cookie 头部。该头部包含了 sessionId。Set-Cookie 格式如下,具体请看 Cookie 详解
Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure] - 在客户端发起的第二次请求,假如服务器给了 set-Cookie,浏览器会自动在请求头中添加 cookie
- 服务器接收请求,分解 cookie,验证信息,核对成功后返回 response 给客户端
session 的缺点:比如 A 服务器存储了 Session,就是做了负载均衡后,假如一段时间内 A 的访问量激增,会转发到 B 进行访问,但是 B 服务器并没有存储 A 的 Session,会导致 Session 的失效
对比
- cookie 只是实现 session 的其中一种方案。虽然是最常用的,但并不是唯一的方法。禁用 cookie 后还有其他方法存储,比如放在 url 中
- 现在大多都是 Session + Cookie,但是只用 session 不用 cookie,或是只用 cookie,不用 session 在理论上都可以保持会话状态。可是实际中因为多种原因,一般不会单独使用
- 用 session 只需要在客户端保存一个 id,实际上大量数据都是保存在服务端。如果全部用 cookie,数据量大的时候客户端是没有那么多空间的。
- 如果只用 cookie 不用 session,那么账户信息全部保存在客户端,一旦被劫持,全部信息都会泄露。并且客户端数据量变大,网络传输的数据量也会变大
cookie
首先,客户端会发送一个 http 请求到服务器端。
服务器端接受客户端请求后,建立一个 session,并发送一个 http 响应到客户端,这个响应头,其中就包含 Set-Cookie 头部。该头部包含了 sessionId。Set-Cookie 格式如下,具体请看 Cookie 详解Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
在客户端发起的第二次请求,假如服务器给了 set-Cookie,浏览器会自动在请求头中添加 cookie
服务器接收请求,分解 cookie,验证信息,核对成功后返回 response 给客户端
缺点:请求头额外的开销、不安全、对负责请求的应用 cookie 大小不够
改变 cookie
如果想改变一个已存在的 Cookie(通过 Set-Cookie 或 document.cookie ),需要 key、domain、path 和 secure 都匹配,否则会出现两个同名的 Cookie,在发起请求的时候如果满足条件则都会被带上,后端无法区分
cookie 的固有属性

参考:cookie都有哪些属性 - 掘金
Name、Value、Domain、Path、Expires/Max-age、Size、HttpOnly、Secure、SameSite 和 Priority
name 和 value
Name 和 Value 是一个键值对。Name 是 Cookie 的名称,Cookie 一旦创建,名称便不可更改,一般 名称不区分大小写;Value 是该名称对应的 Cookie 的值,如果值为 Unicode 字符,需要为字符编码。如果值为二进制数据,则需要使用 BASE64 编码。
Domain
Domain 的设置是对子域生效的,服务端设置。但是不能将其设置为服务器所属域之外的域
Expires / Max-age
若不设置则默认页面关闭时删除该 Cookie
SameSite
SameSite 用来限制第三方 Cookie,从而减少安全风险。它有 3 个属性,分别是:
- Strict Scrict 最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie
- Lax Lax 默认值。规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。在 Chrome 80 版本之后,Cookie 的 SameSite 由原来的 None 改为了 Lax。
- None 网站可以选择显式关闭 SameSite 属性,将其设为 None。不过,前提是必须同时设置 Secure 属性(Cookie 只能通过 HTTPS 协议发送),否则无效。
Priority
优先级,chrome 的提案,定义了三种优先级,Low/Medium/High,当 cookie 数量超出时,低优先级的 cookie 会被优先清除。
cookie 跨域
只有根域名相同的不同源的 cookie 才有可能实现跨域访问,当前根域名不同不能实现跨域
参考:Cors跨域(二):实现跨域Cookie共享的三要素 - 腾讯云开发者社区-腾讯云
- 前端请求时在
request对象中配置"withCredentials": true; - 服务端在
response的header中配置"Access-Control-Allow-Origin", "http://xxx:${port}"; - 服务端在
response的header中配置"Access-Control-Allow-Credentials", "true"
XMLHttpRequest.withCredentials 属性是一个 Boolean 类型,它指示了是否该使用类似 cookies,authorization headers(头部授权) 或者 TLS 客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求。在同一个站点下使用 withCredentials属性是无效的。
- domain 跟 path 属性与请求的域名路径匹配,Cookie 才会被携带
- 如果有 Secure 属性,请求协议必须是 HTTPS
- 跨域 AJAX 请求不会携带 Cookie,如果需要携带需要配置 withCredentials 请求头以及 CORS 响应头
- 如果请求跨站了,还要判断 SameSite 属性是否满足发送条件
token
- token 存在哪儿都行,客户端可存放在 localstorage 或者 cookie,而服务器端则会存放于数据库 (服务器端的 session 是直接放在内存中的)
- cookie 举例: 服务员看你的身份证后,给你一个编号,以后,进行任何操作,都出示编号,然后服务员再去查看你是谁
token 举例: 直接给服务员看自己的身份证 - token 的可拓展性更强。
- token 可抵御 csrf,因为 cookie 容易伪造,但是 token 是不容易伪造的。
Token 完全由应用管理,所以它可以避开同源策略
Token 可以避免 CSRF 攻击
Token 可以是无状态的,可以在多个服务间共享
jwt 的固有属性
Header.Payload.Signature
令牌的类型(即 JWT)和使用的签名算法- 声明是有关实体(通常是用户)和其他数据的声明
- JWT 的第三部分是一个签证信息,这个签证信息由三部分组成
- header (base64 后的)
- payload (base64 后的)
- secret

参考
JSON Web Token 入门教程 - 阮一峰的网络日志
傻傻分不清之 Cookie、Session、Token、JWT - 掘金