上篇我们讲到浏览器缓存策略中的 HTTP 缓存机制,接下来我们继续浅谈一下浏览器应用层面中的缓存机制,跟上篇一样先看看应用层缓存的类别有哪些?
进入 Chrome 的开发者模式选择 Application 页签,可以看到下图( Background Services 为新版 Chrome 才会有 )
我们来一项项的说明:
栏目 | 项目 | 描述 |
---|---|---|
Application | Manifest | Manifest ( Web应用程序清单 ) 在一个JSON文本文件中提供有关应用程序的信息(如名称,作者,图标和描述)。Manifest 的目的是将Web应用程序安装到设备的主屏幕,为用户提供更快的访问和更丰富的体验。 |
- | Service Workers | Service Workers 是一个 web API,是 Web Workers 的一种实现,功能是可以拦截、处理请求,配合 CacheStorage 等 API,可以做到将资源存储到本地等,实现离线访问。(也就是我们上篇所提及的 HTTP 缓存位置的其中一项) |
- | Clear storage | 清理浏览器缓存工具。 |
Storage(缓存) | Local Storage | 用于长久保存整个网站的数据(键值对存储方式),保存的数据没有过期时间,直到手动去删除。也就是我们常用的localStorage.setItem ,getItem() ,removeItem() ,clear() ,的存储位置。 |
- | Session Storage | 用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。API与local一样,只是生命周期不同,存储数据大小两个都是5MB。 |
- | indexedDB | 浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。 |
- | Web SQL | Web SQL 数据库 API 并不是 HTML5 规范的一部分,但是它是一个独立的规范,引入了一组使用 SQL 操作客户端数据库的 API。 |
- | Cookies | 指某些网站为了辨别用户身份、进行 session (存储在服务端的用户信息)跟踪而储存在用户本地终端上的数据(通常经过加密),一般大小只有4k,会赋在每次的请求头中。 |
Cache(贮存物) | Cache storage | CacheStorage 接口表示 Cache 对象的存储。为 Service Workers 与其他 Worker 服务 |
- | Application storage | 是 HTML5 新增的一个离线应用功能,在对应用进行缓存的时候需要一个 manifest 文件。 |
Background Services (后台服务) | Background Fetch | 用于生成在后台挂起的 fetch 资源任务 |
- | Background Sync | 生成在后台挂起执行的同步任务 |
Frames(构架) | top | 用于显示当前页面所有的资源列表,包括字体、图片、js源码等 |
大体上我们可以把他们分成两类,一种是实现跟踪浏览器用户身份功能的 Cookies 与 Session, 以及为了解决 Cookies 弊端在 HTML5 时代所发展出来的 Web Storage。另一种是针对 PWA ( Progressive Web App)即渐进式 web 应用服务,是为了下一代 web APP 服务的缓存机制。
Cookies
随着 Web 的蓬勃发展,在业务上出现用户身份的概念,比如在论坛这一应用场景中。Cookies 的出现,提供了存储用户信息的功能,免除了客户从一个页面跳转至另一个页面时重新输入认证信息。
Cookies 作为最古老且很成熟的 HTTP 状态保持办法又有哪些特点呢?
1. Cookies 的组成
Cookie 是一段不超过4KB的小型文本数据,由一个名称(Name)、一个值(Value)和其它几个用于控制 Cookie 有效期、安全性、使用范围的可选属性组成。
成员 | 描述 |
---|---|
Name/Value | 设置 Cookie 的名称及相对应的值,保存访问令牌。 |
Expires(期限) | 设置 Cookie 的生存期。有两种存储类型的 Cookie :会话性 与 持久性。Expires 属性缺省时,为会话性 Cookie,仅保存在客户端内存中,并在用户关闭浏览器时失效;持久性 Cookie 会保存在用户的硬盘中,直至生存期到或用户直接在网页中单击“注销”等按钮结束会话时才会失效。 |
Path | 定义了 Web 站点上可以访问该Cookie的目录。 |
Domain(领域) | 指定了可以访问该 Cookie 的 Web 站点或域。Cookie 机制并未遵循严格的 同源策略,允许一个子域可以设置或获取其父域的 Cookie。当需要实现单点登录方案时,Cookie 的上述特性非常有用,然而也增加了 Cookie 受攻击的危险,比如攻击者可以借此发动会话定置攻击。因而,浏览器禁止在 Domain 属性中设置.org、.com 等通用顶级域名、以及在国家及地区顶级域下注册的二级域名,以减小攻击发生的范围。 |
Secure | 指定是否使用 HTTPS 安全协议发送 Cookie。使用 HTTPS 安全协议,可以保护 Cookie 在浏览器和 Web 服务器间的传输过程中不被窃取和篡改。该方法也可用于 Web 站点的身份鉴别,即在 HTTPS 的连接建立阶段,浏览器会检查 Web 网站的 SSL 证书的有效性(以前使用网上银行时是不是经常看到 SSL 证书这个东西,当然一般的网站是可以用户自己选择跳过)。 |
HTTPOnly | 用于防止客户端脚本通过 document.cookie 属性访问 Cookie,有助于保护 Cookie 不被跨站脚本攻击窃取或篡改。 |
例子:
document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";
2. Cookies 的流程
-
发布 Cookie
当用户试图访问某 Web 站点中需要认证的资源时,Web 服务器会检查用户是否提供了认证 Cookie,如果没有,则将用户重定向到登录页面。在用户成功登录后,Web 服务器会产生认证 Cookie,并通过 HTTP 响应中的 Set-Cookie 头发送给客户端,用于对用户随后的请求进行检查和验证,接着将用户重定向到初始请求的资源。 -
检索 Cookie
在用户随后的访问请求中,客户端浏览器检索 Path 和 Domain 等属性与用户请求资源相匹配的 Cookie,并将找到的 Cookie 通过 HTTP 请求中的 Cookie 头提交给Web服务器。 -
验证 Cookie
服务器提取客户端浏览器递交的Cookie,验证其中的访问令牌。若合法,则将访问请求的资源发送给客户端浏览器;反之则拒绝用户的访问请求。
3. Cookies 的安全威胁
- Cookies 捕获/重放
攻击者可以通过木马等恶意程序,或使用 跨站脚本 (cross-site scripting,XSS)攻击等手段偷窃存放在用户硬盘或内存中的Cookie。
因为同一个网站下的不同URL的 协议 + 域名/IP + 端口号是符合同源策略的。还是以论坛为例,假设其个人空间的 URL 逻辑为 http://a.com/username
,那么 a 用户的个人空间地址为 http://a.com/a
,b 用户的个人空间地址为 http://a.com/b
。
b 登陆之后在首页发表了一篇文章,添加了以下 js 代码:
let cookie = document.cookie;
那么在 a 登陆之后访问 b 的空间,b 就能拿到 a 的 cookies,从而可以代表 a 更改各种信息,这就是 XSS 攻击。
-
恶意 Cookies
Cookies 是文本文件, 一般情况下认为它不会造成安全威胁。 但是如果在 Cookies 中通过特殊标记语言,引入可执行代码,就很可能给用户造成严重的安全隐患。当页面存在 Cookies 代码注入漏洞,就可以利用修改 Cookies 来执行危险代码。 -
会话定置
会话定置( Session Fixation )攻击是指,攻击者向受害者主机注入自己控制的认证 Cookie 等信息,使得受害者以攻击者的身份登录网站,从而窃取受害者的会话信息。注入Cookie的方法包括:使用跨站脚本或木马等恶意程序;或伪造与合法网站同域的站点,并利用各种方法欺骗用户访问该仿冒网站,从而通过 HTTP 响应中的 Set-Cookie 头将攻击者拥有的该域 Cookies 发送给用户等。 -
CSRF攻击
跨站请求伪造(Cross-Site Request Forgery,简称 CSRF)是指,攻击者可能利用网页中的恶意代码强迫受害者浏览器向被攻击的 Web 站点发送伪造的请求,篡夺受害者的认证 Cookies 等身份信息,从而假冒受害者对目标站点执行指定的操作。
4. Cookies 的安全防护
- Web服务器端防护
- 加入 MAC 以进行完整性校验;
- 防止非法用户非法截获后的重放,可以让用户对相关信息进行数字签名,加强有效性验证;
- 对 Cookie 本身进行随机密钥加密,保证 Cookie 本身的信息安全。
-
客户端浏览器防护
对 Cookie 进行加密。在相应的系统目录下,只可看见一个与 Cookie 相关的加密文件,而且其中的 Cookie 文件,已被浏览器加密,用户不可见,在用户访问特定站点的时候,可由浏览器对 Cookie 文件进行调用并进行解密。 -
主机的安全防护
在浏览器产生 Cookie 加密文件时,在 Cookie 文件中加入一段主机的特征,生成一个双层加密的新的 Cookie 文件;在调用 Cookie 的时候,通过对 Cookie 文件进行主机特征的匹配,选择对内层的文件进行解密调用。
Session
web 的继续发展又引发出了其他用户疼点,比如页面间需要共享的信息多了, Cookies 的储存空间小的问题就出现了;再比如 Cookies 只能以文本格式存储极为不方便,同时每次的 HTTP 请求都会带上 Cookies 增加了宽带的消耗。
这时候 Session 被提出来了,它是一种利用服务端服务器端的机制。通过在 Cookies 中的 Session ID
与服务器校验创建一个被认证的会话,会话内的页面共享 Session 信息。它有以下优点:
- Session 的大小没有限制,因为存储在服务器上;
- Session 通过类似 Hashtable 的数据结构来保存,能支持任何类型的对象;
- 安全性比 Cookies 高,首先要攻破 Session 先要攻破 Cookie,同时 Session ID 是加密的,而 Session ID 需要登录后即创造会话后才有产生,难道比攻破 Cookie 要大得多;
但它依旧有缺点:
- Session 保存的东西越多,就越占用服务器内存,对于用户在线人数较多的网站,服务器的内存压力会比较大。
- 依赖于 Cookie,如果 Cookies 被禁用,则要使用 URL 重写即把 Session ID 拼接在 URL 后面,十分不安全。
由于 Session 是服务端(JAVA)的对象,并不存在于浏览器(JavaScript),要获取 Session 只能通过 Java 获取变成字符串传给浏览器,这里我们就不再展开讨论了。
Web Storage
随着 Html5 的到来,以上两个应用层面的缓存已经不能满足开发者的需求了,更便利的客户端缓存 Web Storage 出现了。它分为两项: Local Storage 与 Session Storage 。
Web Storage 支持协议 + 域名/IP + 端口号的同源策略,非同源不能读取 Storage 里的内容,其属性都允许在浏览器中存储 key/value 对的数据,value 只能存储字符串数据。
那继上文提到的本地存储用户信息的问题, Cookies 因其特性不适合存储,Session 需要 JAVA 的帮助(在混合 APP 中可用利用),它们两都只适合做用户认证而不适合做信息存储,Web Storage 则是带来了本地数据库的功能。
Local Storage
localStorage 用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。localStorage 在PC端浏览器上能够提供5M左右的存储空间,在移动端浏览器上一般提供2.5M左右的存储空间。
语法
window.localStorage
- 保存数据语法
localStorage.setItem("key", "value");
- 读取数据语法
var lastname = localStorage.getItem("key");
- 删除数据语法
localStorage.removeItem("key");
局限
- localStorage 在浏览器的隐私模式下面是不可读取的;
- localStorage 本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡;
- localStorage 不能被爬虫抓取到;
- localStorage 的值类型限定为string类型;
Session Storage
sessionStorage 用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。
语法
window.sessionStorage
- 保存数据语法
sessionStorage.setItem("key", "value");
- 读取数据语法
var lastname = sessionStorage.getItem("key");
- 删除数据语法
sessionStorage.removeItem("key");
他们两同时含有这两个方法 .clear ()
删除所有的数据,key (index)
获取某个索引的key。
Tips:在我做混合 APP 开发时(Hybird App),原生新打开的页面无法共享会话,即 sessionStorage 失效;
PWA
前面我们已经介绍完有关于 Cookies 一系的缓存机制,接下我们简单的谈谈 Google 与 W3C(万维网联盟)所力推的 PWA 以及为其服务的一系列缓存机制。(苹果虽然不太愿意支持,因为会影响它 APP 的抽成,但有 W3C 这个老大在,以后还是会普及的)
PWA 渐进式增强 web 应用, Google 在 2016 年提出概念,于 2017 年落地的 web 技术,而铺垫技术却在很早很早前就开启了(离线缓存概念)。目的就是为移动端利用提供的标准化框架,利用 web 技术实现有着和原生应用相近的用户体验。
大家在用手机浏览网页时应该能看到下面这个选项:
点击就可以在手机主屏生产 PWA 版本的离线应用,国外的 Facebook 、Twitter 等都实现得非常好了,它们是可以安装到设备的主屏幕的网络应用程序,而不需要用户通过应用商店,伴随着其他功能, 比如离线可用和接收推送通知。
Manifest
Manifest(Web 应用程序清单)是在一个JSON文本文件中提供有关应用程序的信息(如名称,作者,图标和描述),是 渐进式Web应用程序(PWA) 的 Web 技术集合的一部分。
Manifest 服务于 Service Workers、Cache Storage、Application Cache( Service Workers 取代 )、BackGround Services,这四项缓存都是依赖 Manifest 模块资源清单实现资源的管理的。
<link rel="manifest" href="/manifest.json">
至于这个清单怎么用这里就不细讲了,传送门。
而 IndexedDB、Web SQL(废弃,被 IndexedDB 取代 ),则是前端的数据库,实际就是为了构建出统一的 APP 应用开发环境所做的铺垫。
关注我 Max_Law,学习更多前端知识。