不需要走网络、不会影响资源的加载流程
Cookie
Cookie 是浏览器用来存储少量文本数据的小型文件 (≤ 4KB ),每次发送请求的时候都会自动携带 和这个域名关联的 Cookie,主要用于例如
会话管理(Session ID)、登录状态(SSO):方便服务器端识别是谁
个性化设置,如
jsx
theme=dark
language=zh
跨站跟踪,例如页面中嵌入了广告商的 img ,广告商域名会设置自己的 Cookie ,当访问另一个同域的网站时就能识别出是同一个用户
内容
Cookie 存储在浏览器内部,每个域名都有自己Cookie的
- 名称
- 值
- 过期时间
- 安全属性
浏览器会自动管理它们,开发者无法指定目录存放位置
生命周期
Cookie有两种
1. 会话 Cookie ( Session Cookie )
没有设置 expires 或 max-age ,当浏览器关闭时自动删除
2. 持久化 Cookie ( Persistent Cookie )
设置了过期时间,到时候会自动删除,例如
jsx
Set-Cookie: token=abc123; Max-Age=3600
Max-Age 的单位是 秒 ,表示一个小时后自动删除
Cookie 是如何跟随请求的
例如 服务器创建Cookie 并返回
jsx
Set-Cookie: session_id=xyz; HttpOnly; Secure; Path=/;
那么 浏览器自动存储和管理 ,之后访问同域名页面时会自动携带
jsx
Cookie: session_id=xyz
安全隐患
Cookie 被偷走或者滥用都是无感的
1. XSS
在页面中注入 JS ,读取
jsx
document.cookie
(但是不能读 HttpOnly 的:开启后只能服务器使用、防止JS读Cookie)
如果被读到了 session_id 或 token 那登录态就泄露了,对方可以直接设置同样的 Cookie 然后伪装身份进行登录,即 会话挟持
2. CSRF
利用请求同域时会自动带上Cookie的特性
例如之前你登录过 bank.com ,后面你不小心点击了 bank.com/transer 导致能拿到你的 Cookie 然后识别你的身份进行了操作
-
可以通过设置 SameSite = Strict 任何跨站都不带 Cookie,
或者设置为 Lax ,那么跳转进来是可以携带的
-
在敏感信息上设置一个隐藏的随机 token ,例如
jsx<input type = "hidden" name = "csrf_token" value = "xxxx">每次 POST/操作请求 都必须带上这个 token,服务器验证 token 是否匹配、是否过期
重要属性
1. secure
确保 Cookie 只能在 HTTPS 下传输,防止 HTTP 明文环境被窃听
2. HttpOnly
3. SameSite
4. Path
指定 Cookie 作用的路径,例如 Path=/a 那么只有在 /a 时会发送 Cookie
5. Domain
限制 Cookie 生效范围
例如设置了 Domain = k.com,
Token结合Cookie实现登录管理
1. 长短期双Token - 前后端分离
短期令牌 Access Token 放在前端例如 localStorage 中
长期令牌 Refresh Token 放在 HttpOnly Cookie 中供服务器端使用(防XSS),且开启 Secure
-
登录
- 前端发送 POST 请求
- 服务器验证成功后返回 长期令牌
jsxSet-Cookie: refresh_token=xxx; HttpOnly; Secure; SameSite=Lax; Max-Age=7d浏览器自动放到 Cookie 中;
并在 响应体 中返回 短期令牌
jsx{ "access_token": "xxx", "expire_in": 900 }前端保存到内存(JS变量)或者 localStorage 中
-
调用业务 API 时,请求手动携带 Access Token
jsxGET /api/userinfo Authorization: Bearer ACCESS_TOKEN- 没有过期的话直接服务器验证然后返回
- 如果服务器返回 401 表示短期令牌 Access Token 过期了,那么前端立即调用 POST /api/refresh_token 携带上 长期令牌 refresh_token 去请求,服务器端验证长期令牌成功后会在响应体中返回新的 短期令牌 ,前端更新 Access Token
- 如果返回 403 表示长期令牌也过期了,那么就需要重新登录
2. 所有 Token 都放在 HttpOnly Cookie 中
- 在登录后服务器返回 Cookie
- 前端访问 API 的时候,不用手动个携带信息(Cookie请求时自动携带了
- 后端直接从 Cookie 中读取 token 进行验证
需要注意 CSRF ,得打开 SameSite 为 Strict 或 Lax
3. 传统 Session 模式
Cookie 只存 sessionId , Token 由服务器端管理
- 登录后服务器返回 Cookie 是 SessionId
- 前端每次请求都会携带这个 SessionId Cookie
如果 Cookie 是 Session 会话级的,那么页面关闭就需要再次登录请求
如果是 持久化 Cookie 的话就看过期时间
SSO单点登录 - cookie
浏览器端自动附带凭证的唯一可靠机制就是 Cookie ,浏览器不会自动携带 localStorage 、sessionStorage、IndexedDB 的数据
4KB
所以要实现自动登陆、无感跳转本质就只有 Cookie 能进行验证
开启 SameSite = None; Secure
localStorage、SessionStorage
5MB
是浏览器暴露给 JS 的持久化存储方式,通过键值对形式进行管理,属于 Web Storage ,无法像缓存一样参与资源加载