- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前端的储存技术
- 打开
Chrome浏览器,F12打开控制台,点击Application项,侧边栏Storage栏目下的6种选项,都是web端的储存方式- LocalStorage
- SessionStorage
- Cookies
- IndexedDB
- Web SQL
- Trust Tokens
常用前三种存储方式,这里重点讲
cookies
Cookies
-
定义:
- HTTP Cookie,通常直接叫做cookie,用于客户端存储会话信息的,该标准要求服务器对任意HTTP请求发送Set-Cookie HTTP头作为响应的一部分,其中包含会话信息。
- Cookie保存在客户端浏览器中,作为Http请求的一部分,浏览器请求页面时,它会被通过Http请求头的形式自动发送过去。
第一次请求时,服务器端将cookie存放在响应头的
Set-Cookie字段中,发送到客户端,客户端将cookies数据存在在浏览器内存里面。
在下一次请求时,浏览器将会自动把cookies数据存放在请求头的Cookie字段中,带回服务器端。 -
配置选项功能详解:
-
Name & Value
- Name表示Cookie的名称,服务器就是通过name属性来获取某个Cookie的值。
- Value表示Cookie的值,多数情况下服务器会把这个value当做一个Key去缓存中查询保存的数据。
-
SameSite:
Strict,Lax,NoneSameSite属性用来限制第三方 Cookie,使cookie不能随着跨域请求一起发送,从而防范跨站请求伪造攻击(CSRF),减少安全风险。
-
Strict: 最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。跨域和跨站:
跨域: 当站点和站点之间有着相同的scheme,相同的hostname和相同的port时,被认为是同域。这三个中的任何一个不相同时被认为是跨域。
跨站: 当站点和站点的顶级域名与它前面的域(不需要考虑协议和端口)都一致时,被认为是同站。反之被认为是跨站。
判断手段: 通过检查HTTP请求头选项Sec-Fetch-Site的值,可以确定请求与请求之间是“同站same-site”,“同源same-origin”还是“跨站cross-site” -
Lax: 规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求(链接,预加载请求,GET 表单)除外。 -
None: None无论是否跨站都会发送 Cookie, 但必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送)才有作用,否则将会遭到客户端的Block拒绝,无法写入cookie。
Cookie 往往用来存储用户的身份信息,恶意网站可以设法伪造带有正确 Cookie 的 HTTP 请求,这就是 CSRF 攻击,设置了
Strict或Lax以后,基本就杜绝了 CSRF 攻击。Chrome93 已将
Lax变为SameSite默认设置,无法通过chrome://flags/网站选择显式关闭SameSite属性将其设为None。 -
HttpOnly: true/false;- 设置了 HttpOnly 属性为true的 cookie,将不能使用 JavaScript 经由
Document.cookie属性、XMLHttpRequest和Request APIs进行访问,以防范跨站脚本攻击。当HttpOnly为true时,客户端对cookie既无法获取修改,也无法删除。
客户端也无法去添加带有HttpOnly属性的cookie, 但若想在客户端调试HttpOnly属性,可以在Chrome打开Application,手动去把cookie相应的HttpOnly属性进行打勾
- 设置了 HttpOnly 属性为true的 cookie,将不能使用 JavaScript 经由
-
Secure: true/false;- 一个带有 secure 安全属性的 cookie, 只有在请求使用SSL和HTTPS协议的时候才会被发送到服务器。
-
Expires/Max-AgeExpires为 Cookie 的删除设置一个过期的GMT日期Max-Age设置一个 Cookie 将要过期的秒数- 注意:
-
在 Cookie 中同时设置了
Expires和Max-Age, 将会忽略expires,取Max-Age值 -
如果
Expires和Max-Age两个都没有显式设置,Cookie将会作为一个Session Cookie,当关闭浏览器时它会被删除Session Cookie数据保存在内存中,如果是设置了过期时间,浏览器会把cookie保存在硬盘内 -
浏览器根据本地时间,决定 Cookie 是否过期,到了指定时间以后,浏览器就不再保留这个 Cookie
由于本地时间未必精准,所以无法保证Cookie一定会在服务器指定的时间过期。
-
-
Domain- Cookie的作用域:Cookie的作用域是
Domain本身,以及Domain下的所有子域名。Cookie只有在当前域和子域中查看,在父域或者兄弟域之中是无法跨域读取cookie的
- 参数值:
- 当没有显式设置
Domain值时,Domain值默认为当前域名。- Cookie是前端设置的,当前域名便是前端网站的访问域名
- Cookie是后端设置的,当前域名便是后端的接口域名
- 参数值可以为设置父域名以及自身,但不能设置其它域名,包括子域名,否则cookie不起作用。
如果要在多个二级域名中共享Cookie的话,那么得将Domain的属性设置为顶级域名。
在设置为顶级域名时,记得以.开头,如.baidu.com
- 当没有显式设置
- Cookie的作用域:Cookie的作用域是
-
Path: 在Domain的作用域下,进一步通过域名路径限制访问。- 参数值:默认为根路径
/,即Domain域名作用域下的所有页面路径,皆可访问到cookie
- 参数值:默认为根路径
-
SameParty:目前只在Chrome看到该规范SameParty属性需要与First-Party Sets策略搭配才能使用,目前属于feature功能,期待后面广泛支持各种浏览器,Chrome:Cookie SameParty
未来SameParty与SameSite组合使用,将实现cookie得以跨域、跨站访问- 参考文档:详解 Cookie 新增的 SameParty 属性
-
Priority:优先字段,值为 low|medium|high,medium 为默认值。目前只在Chrome看到该规范- 目的:旨在减少 cookie“驱逐”(即在超过每个域的 cookie 容量限制时删除)对用户体验的影响。
- 基本场景:
- 场景问题:长期存在的登录会话 cookie 由于其年龄而被驱逐,从而迫使用户丢失会话。当用户重新进行身份验证时,会发生 Cookie“恢复”。
- 建议解决方案:为 cookie 添加一个“优先级”字段,从而允许服务器保护重要的 cookie。
- 作用:
- 在重新验证 cookie 时对其进行优先级排序。
- 当 cookie 超过每个域的 cookie 容量时,它们会被删除。
- cookie-priority 允许服务器以较低的优先级删除旧的 cookie,并在更高优先级的 cookie 上停留更长时间。
-
-
Cookie实践:
- 运行环境: Google Chrome 版本 94.0.4606.54(正式版本) (64 位)
-
Chrome Platform Status: Cookie
Cookies default to SameSite=Lax
- 前端设置方法:
- HTTP cookies
- 原生示例:
let date = new Date(); date.setDate(date.getDate()+30); date.toGMTString(); document.cookie="tokens=GFRTDDFG;SameSite=Strict;Secure;Expires="+ date +";" document.cookie="tokens=GFRTDDFG;SameSite=Strict;Secure;max-age=1000;" - vue示例(vue-cookies)
Vue.$cookies.set("use_path_argument","value",null, null, null, null, "Lax"); // Vue.$cookies.set(keyName, value[, expireTimes[, path[, domain[, secure[, sameSite]]]]])
- 后端设置方法:Node示例
// 方法1. res.setHeader("Set-Cookie", "id=123456; Path=/;SameSite=None; Secure") // 方法2. const oneDayToSeconds = 24 * 60 * 60; const token = 123456; res.cookie('token', token, { maxAge: oneDayToSeconds, // Cookie 将要过期的秒数,若没有设置,这个 Cookie 将会一直存在直到你关闭浏览器,这种称之为 `Session Cookie` httpOnly: false, // You can't access these tokens in the client's javascript sameSite: '', // set sameSite - should be one of `None`, `Strict` or `Lax`. // signed: true, // use the secret passed into `express.cookieParser('secret')` to sign the value. secure: process.env.NODE_ENV === 'production'? true: false // Forces to use https in production })
- 运行环境: Google Chrome 版本 94.0.4606.54(正式版本) (64 位)