面向 Web 开发人员版本 - 最后更新时间 2024 年 9 月 12 日
在所有当前引擎中支持。
本规范引入了两种相关的机制,类似于 HTTP 会话 cookie,用于在客户端存储键值对。 [COOKIES]
第一种机制设计用于用户执行单个事务的场景,但可能在不同的窗口中同时执行多个事务。
Cookie 在处理这种情况时并不理想。例如,用户可能在两个不同的窗口中购买机票,使用同一个网站。如果网站使用 cookie 来跟踪用户正在购买的机票,那么当用户在两个窗口中从一个页面点击到另一个页面时,正在购买的机票将“泄漏”到另一个窗口,可能会导致用户在没有注意到的情况下购买两张同一航班的机票。
为了解决这个问题,本规范引入了 sessionStorage
获取器。网站可以将数据添加到会话存储中,并且该数据可以在该窗口中打开的同一个网站的任何页面访问。
例如,页面可以有一个复选框,用户选中它表示他们想要购买保险。
< label >
< input type = "checkbox" onchange = "sessionStorage.insurance = checked ? 'true' : ''" >
I want insurance on this trip.
</ label >
然后,后续页面可以通过脚本检查用户是否选中了复选框。
if ( sessionStorage. insurance) { ... }
如果用户在该网站上打开了多个窗口,每个窗口都将拥有其自己的独立的会话存储对象副本。
第二种存储机制是为跨越多个窗口,并在当前会话结束后持续存在的存储而设计的。特别是,Web 应用程序可能希望将兆字节的用户数据(例如,整个用户创作的文档或用户的邮箱)存储在客户端,以提高性能。
同样,Cookie 也不适合处理这种情况,因为它们会与每个请求一起传输。
localStorage
获取器用于访问页面的本地存储区域。
example.com 上的网站可以通过在页面底部添加以下内容来显示用户加载该页面的次数:
< p >
You have viewed this page
< span id = "count" > an untold number of</ span >
time(s).
</ p >
< script >
if ( ! localStorage. pageLoadCount)
localStorage. pageLoadCount = 0 ;
localStorage. pageLoadCount = parseInt( localStorage. pageLoadCount) + 1 ;
document. getElementById( 'count' ). textContent = localStorage. pageLoadCount;
</ script >
每个网站都有自己独立的存储区域。
localStorage
获取器提供了对共享状态的访问。本规范没有定义与多进程用户代理中其他代理集群的交互,并且作者鼓励假设不存在锁定机制。例如,网站可能会尝试读取键的值,增加其值,然后使用新值将其写回,并使用新值作为会话的唯一标识符;如果网站在两个不同的浏览器窗口中同时执行此操作两次,它可能会最终为两个会话使用相同的“唯一”标识符,从而可能产生灾难性的影响。
在所有当前引擎中支持。
Storage
接口storage.length
返回键值对的数量。
storage.key (n)
返回第 n 个键的名称,如果 n 大于或等于键值对的数量,则返回 null。
value = storage.getItem (key)
value = storage[key]
返回与给定 key 关联的当前值,如果给定 key 不存在,则返回 null。
storage.setItem (key, value)
storage[key] = value
将由 key 标识的对的值设置为 value,如果之前不存在 key 的键值对,则创建一个新的键值对。
如果无法设置新值,则抛出 "QuotaExceededError
" DOMException
异常。(设置可能会失败,例如,用户禁用了该网站的存储,或者超过了配额。)
在持有等效 Storage
对象的 Window
对象上调度 storage
事件。
storage.removeItem (key)
delete
storage[key]如果存在具有给定 key 的键值对,则删除具有给定 key 的键值对。
在持有等效 Storage
对象的 Window
对象上调度 storage
事件。
storage.clear()
删除所有键值对(如果存在)。
在持有等效 Storage
对象的 Window
对象上调度 storage
事件。
sessionStorage
获取器window.sessionStorage
返回与该 window 的来源的会话存储区域关联的 Storage
对象。
如果 Document
的 来源 是一个 不透明来源,或者请求违反了策略决策(例如,如果用户代理被配置为不允许页面持久化数据),则抛出 "SecurityError
" DOMException
。
localStorage
获取器window.localStorage
返回与 window 的来源的本地存储区域关联的 Storage
对象。
如果 Document
的 来源 是一个 不透明来源,或者请求违反了策略决策(例如,如果用户代理被配置为不允许页面持久化数据),则抛出 "SecurityError
" DOMException
。
StorageEvent
接口在所有当前引擎中支持。
event.key
返回正在更改的存储项的键。
event.oldValue
返回正在更改其值的存储项的键的旧值。
event.newValue
返回正在更改其值的存储项的键的新值。
event.url
返回其存储项已更改的文档的 URL。
event.storageArea
返回受影响的 Storage
对象。
第三方广告商(或能够将内容分发到多个网站的任何实体)可以使用存储在其本地存储区域中的唯一标识符来跨多个会话跟踪用户,从而构建用户兴趣的配置文件,以实现高度针对性的广告。与了解用户真实身份的网站(例如,需要身份验证凭据的电子商务网站)结合使用,这可能会使压制性团体能够比在纯粹匿名使用网络的世界中更准确地针对个人。
可以使用多种技术来减轻用户追踪的风险
用户代理可能会限制对 localStorage
对象的访问,使其仅限于来自 活动文档 的域名的脚本,例如,拒绝来自其他域名页面在 iframe
中运行的脚本访问 API。
用户代理可能会(可能以用户配置的方式)在一段时间后自动删除存储的数据。
例如,用户代理可以配置为将第三方本地存储区域视为仅限会话的存储,并在用户关闭所有可以访问该存储区域的 导航器 后删除数据。
这可以限制网站跟踪用户的可能性,因为网站只有在用户使用该网站本身进行身份验证(例如,进行购买或登录服务)时才能跨多个会话跟踪用户。
但是,这也降低了 API 作为长期存储机制的实用性。如果用户不完全了解数据过期的影响,它也可能会使用户的数据面临风险。
如果用户尝试通过清除 cookie 来保护隐私,但没有同时清除本地存储区域中的数据,网站可以通过将这两个功能用作冗余备份来挫败这些尝试。用户代理应以有助于用户理解这种可能性并使他们能够同时删除所有持久存储功能中的数据的方式来呈现清除这些数据的界面。 [COOKIES]
用户代理可能允许网站以不受限制的方式访问会话存储区域,但要求用户授权访问本地存储区域。
用户代理可能会记录包含来自导致存储数据的第三方来源内容的网站的 来源。
如果此信息随后用于呈现当前处于持久存储中的数据的视图,它将允许用户做出关于要修剪持久存储的哪些部分的明智决定。结合黑名单(“删除此数据并阻止此域再次存储数据”),用户可以将持久存储的使用限制在他们信任的网站上。
用户代理可能允许用户共享其持久存储域黑名单。
这将允许社区共同努力保护他们的隐私。
虽然这些建议可以防止对用户跟踪使用此 API,但它们并没有完全阻止它。在一个域内,网站可以在会话期间继续跟踪用户,然后将所有这些信息以及网站获得的任何识别信息(姓名、信用卡号码、地址)传递给第三方。如果第三方与多个网站合作以获取此类信息,仍然可以创建个人资料。
但是,即使没有任何来自用户代理的合作,用户跟踪在某种程度上也是可能的,例如通过在 URL 中使用会话标识符,这是一种已经广泛用于无害目的的技术,但很容易被重新用于用户跟踪(甚至追溯地)。然后可以使用访客的 IP 地址和其他用户特定数据(例如用户代理标头和配置设置)将此信息与其他网站共享,以将单独的会话合并成连贯的用户个人资料。
由于存在 DNS 欺骗攻击的可能性,无法保证声称来自特定域的宿主实际上确实来自该域。为了减轻这种情况,页面可以使用 TLS。使用 TLS 的页面可以确保只有用户、代表用户工作的软件以及使用 TLS 并拥有标识其来自同一域的证书的其他页面可以访问其存储区域。
不同的作者共享一个主机名,例如在现已停用的 geocities.com
上托管内容的用户,都共享一个本地存储对象。没有限制按路径名访问的功能。因此,强烈建议共享主机上的作者避免使用这些功能,因为其他作者可以很容易地读取数据并覆盖数据。
即使提供了路径限制功能,传统的 DOM 脚本安全模型也会很容易绕过此保护并从任何路径访问数据。