type
status
date
slug
summary
tags
category
icon
password
Edited
Sep 15, 2022 01:17 PM
Created
Sep 13, 2022 02:14 PM
Cookie
Cookie 是直接存储在浏览器中的一小串数据。它们是 HTTP 协议的一部分,由 RFC 6265 规范定义。
Cookie 通常是由 Web 服务器使用响应
Set-Cookie HTTP-header 设置的。然后浏览器使用 Cookie HTTP-header 将它们自动添加到(几乎)每个对相同域的请求中。使用document.cookie属性从浏览器访问 cookie
document.cookie
document.cookie 的值由 name=value 对组成,以 ; 分隔。每一个都是独立的 cookie。document.cookie 是一个 访问器(getter/setter)。对其的赋值操作会被特殊处理。对
document.cookie 的写入操作只会更新其中提到的 cookie,而不会涉及其他 cookie。因为
document.cookie= 操作不是重写整所有 cookie。它只设置代码中提到的 cookie user。从技术上讲,cookie 的名称和值可以是任何字符。为了保持有效的格式,它们应该使用内建的
encodeURIComponent 函数对其进行转义限制
encodeURIComponent编码后的name=value对,大小不能超过 4KB。因此,我们不能在一个 cookie 中保存大的东西。
- 每个域的 cookie 总数不得超过 20+ 左右,具体限制取决于浏览器。
参数
path
path=/mypathurl 路径前缀必须是绝对路径。它使得该路径下的页面可以访问该 cookie。默认为当前路径。
如果一个 cookie 带有
path=/admin 设置,那么该 cookie 在 /admin 和 /admin/something 下都是可见的,但是在 /home 或 /adminpage 下不可见。通常,我们应该将
path 设置为根目录:path=/,以使 cookie 对此网站的所有页面可见。domain
domain=site.comdomain 控制了可访问 cookie 的域。但是在实际中,有一些限制。我们无法设置任何域。
默认情况下,cookie 只有在设置的域下才能被访问到。
请注意,默认情况下,cookie 也不会共享给子域,例如
forum.site.com。如果我们想允许像
forum.site.com 这样的子域在 site.com 上设置 cookie,也是可以实现的。因此,当在
site.com 设置 cookie 时,我们应该明确地将 domain 选项设置为根域:domain=site.com。那么,所有子域都可以访问到这样的 cookie。expires & max-age
默认情况下,如果一个 cookie 没有设置这两个参数中的任何一个,那么在关闭浏览器之后,它就会消失。此类 cookie 被称为 "session cookie”。
为了让 cookie 在浏览器关闭后仍然存在,我们可以设置
expires 或 max-age 选项中的一个。expires=Tue, 19 Jan 2038 03:14:07 GMT日期必须完全采用 GMT 时区的这种格式(可以使用
date.toUTCString 来获取它)示例:一天后过期
max-age=3600指明了 cookie 的过期时间距离当前时间的秒数(上例就是1h后过期)
secure
secureCookie 应只能被通过 HTTPS 传输。
默认情况下,如果我们在
http://site.com 上设置了 cookie,那么该 cookie 也会出现在 https://site.com 上,反之亦然。使用此选项,如果一个 cookie 是通过
https://site.com 设置的,那么它不会在相同域的 HTTP 环境下出现,例如 http://site.com。如果一个 cookie 包含绝不应该通过未加密的 HTTP 协议发送的敏感内容,那么就应该设置
secure 标识。samesite
这是另外一个关于安全的特性。它旨在防止 XSRF(跨网站请求伪造)攻击。
Cookie 的
samesite 选项提供了另一种防止此类攻击的方式,(理论上)不需要要求 “XSRF 保护 token”。samesite=strict(和没有值的samesite一样)
如果用户来自同一网站之外,那么设置了
samesite=strict 的 cookie 永远不会被发送。换句话说,无论用户是通过邮件链接还是从
evil.com 提交表单,或者进行了任何来自其他域下的操作,cookie 都不会被发送。samesite=lax- HTTP 方法是“安全的”(例如 GET 方法,而不是 POST)。
- 该操作执行顶级导航(更改浏览器地址栏中的 URL)。
一种更轻松的方法,该方法还可以防止 XSRF 攻击,并且不会破坏用户体验。
宽松(lax)模式,和
strict 模式类似,当从外部来到网站,则禁止浏览器发送 cookie,但是增加了一个例外。如果以下两个条件均成立,则会发送含
samesite=lax 的 cookie:所有安全的 HTTP 方法详见 RFC7231 规范。基本上,这些都是用于读取而不是写入数据的方法。它们不得执行任何更改数据的操作。跟随链接始终是 GET,是安全的方法。
这通常是成立的,但是如果导航是在一个
<iframe> 中执行的,那么它就不是顶级的。此外,用于网络请求的 JavaScript 方法不会执行任何导航,因此它们不适合。httpOnly
这个选项禁止任何 JavaScript 访问 cookie。我们使用
document.cookie 看不到此类 cookie,也无法对此类 cookie 进行操作。这是一种预防措施,当黑客将自己的 JavaScript 代码注入网页,并等待用户访问该页面时发起攻击,而这个选项可以防止此时的这种攻击。这应该是不可能发生的,黑客应该无法将他们的代码注入我们的网站,但是网站有可能存在 bug,使得黑客能够实现这样的操作。
XSRF攻击
想象一下,你登录了
bank.com 网站。此时:你有了来自该网站的身份验证 cookie。你的浏览器会在每次请求时将其发送到 bank.com,以便识别你,并执行所有敏感的财务上的操作。现在,在另外一个窗口中浏览网页时,你不小心访问了另一个网站
evil.com。该网站具有向 bank.com 网站提交一个具有启动与黑客账户交易的字段的表单 <form action="https://bank.com/pay"> 的 JavaScript 代码。你每次访问
bank.com 时,浏览器都会发送 cookie,即使该表单是从 evil.com 提交过来的。因此,银行会识别你的身份,并执行真实的付款。
这就是所谓的“跨网站请求伪造(Cross-Site Request Forgery,简称 XSRF)”攻击。
Cookie 函数
getCookie(name)
setCookie(name, value, options)
deleteCookie(name)
GDPR
GDPR
欧洲有一项名为 GDPR 的立法,该法规针对网站尊重用户实施了一系列规则。其中之一就是需要明确的许可才可以跟踪用户的 cookie。
这仅与跟踪/识别/授权 cookie 有关。
所以,如果我们设置一个只保存了一些信息的 cookie,但是既不跟踪也不识别用户,那么我们可以自由地设置它。
但是,如果我们要设置带有身份验证会话(session)或跟踪 id 的 cookie,那么必须得到用户的允许。
LocalStorage & sessionStorage
Web 存储对象
localStorage 和 sessionStorage 允许我们在浏览器上保存键/值对。它们有趣的是,在页面刷新后(对于
sessionStorage)甚至浏览器完全重启(对于 localStorage)后,数据仍然保留在浏览器中。与 cookie 不同,Web 存储对象不会随每个请求被发送到服务器。因此,我们可以保存更多数据。大多数现代浏览器都允许保存至少 5MB 的数据(或更多),并且具有用于配置数据的设置。
方法和属性
两个存储对象都提供相同的方法和属性:
setItem(key, value)—— 存储键/值对。
getItem(key)—— 按照键获取值。
removeItem(key)—— 删除键及其对应的值。
clear()—— 删除所有数据。
key(index)—— 获取该索引下的键名。
length—— 存储的内容的长度。
localStorage
localStorage 最主要的特点是:- 在同源的所有标签页和窗口之间共享数据。
- 数据不会过期。它在浏览器重启甚至系统重启后仍然存在。
只需要在同一个源(域/端口/协议),URL 路径可以不同。在所有同源的窗口之间
localStorage 数据可以共享。因此,如果我们在一个窗口中设置了数据,则在另一个窗口中也可以看到数据变化。请注意,键和值都必须是字符串。
遍历
for in 它会遍历所有的键,但也会输出一些我们不需要的内建字段。使用
Object.keys 获取只属于“自己”的键sessionStorage
sessionStorage 对象的使用频率比 localStorage 对象低得多。属性和方法是相同的,但是它有更多的限制:
sessionStorage的数据只存在于当前浏览器标签页。- 具有相同页面的另一个标签页中将会有不同的存储。
- 但是,它在同一标签页下的 iframe 之间是共享的(假如它们来自相同的源)。
- 数据在页面刷新后仍然保留,但在关闭/重新打开浏览器标签页后不会被保留。
sessionStorage 不仅绑定到源,还绑定在同一浏览器标签页。Storage 事件
当
localStorage 或 sessionStorage 中的数据更新后,storage 事件就会触发,它具有以下属性:key—— 发生更改的数据的key(如果调用的是.clear()方法,则为null)。
oldValue—— 旧值(如果是新增数据,则为null)。
newValue—— 新值(如果是删除数据,则为null)。
url—— 发生数据更新的文档的 url。
storageArea—— 发生数据更新的localStorage或sessionStorage对象。
重要的是:该事件会在所有可访问到存储对象的
window 对象上触发,导致当前数据改变的 window 对象除外。如果两个窗口都在监听
window.onstorage 事件,那么每个窗口都会对另一个窗口中发生的更新作出反应。并且,
event.storageArea 包含存储对象 —— sessionStorage 和 localStorage 具有相同的事件,所以 event.storageArea 引用了被修改的对象。我们可能会想设置一些东西,以“响应”更改。这允许同源的不同窗口交换消息。
IndexedDB
IndexedDB 是一个浏览器内建的数据库,它比
localStorage 强大得多。- 通过支持多种类型的键,来存储几乎可以是任何类型的值。
- 支撑事务的可靠性。
- 支持键值范围查询、索引。
- 和
localStorage相比,它可以存储更大的数据量。
IndexedDB 适用于离线应用,可与 ServiceWorkers 和其他技术相结合使用。
基本用法可以用几个短语来描述:
- 获取一个 promise 包装器,比如 idb。
- 打开一个数据库:
idb.openDb(name, version, onupgradeneeded) - 在
onupgradeneeded处理程序中创建对象存储和索引,或者根据需要执行版本更新。
- 对于请求:
- 创建事务
db.transaction('books')(如果需要的话,设置 readwrite)。 - 获取对象存储
transaction.objectStore('books')。
- 按键搜索,可以直接调用对象库上的方法。
- 要按对象字段搜索,需要创建索引。
- 如果内存中容纳不下数据,请使用光标。
参考链接:
- 作者:JinSo
- 链接:https://jinso.top/article/modern-javascript-others-data-storage
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。














