使用ServiceWorker永久浏览器缓存

时间:2017-01-17 14:42:16

标签: javascript security caching service-worker

我正在设计一个JavaScript安全加载器。加载器在index.html中内联。安全加载器的目标是仅加载受信任的JavaScript资源。 index.html的内容主要限于安全加载程序。出于安全考虑,我希望index.html(存储在缓存中)永远不会更改,即使我的网站被黑客攻击

如果服务器无法篡改缓存,我如何缓存index.html?我想知道ServiceWorker是否可以提供帮助。实际上,index.html将注册一个服务工作者从不可变的缓存中获取自己(甚至没有网络请求)。

3 个答案:

答案 0 :(得分:4)

在Chrome中

,您可以使用FileSystem API

http://www.noupe.com/design/html5-filesystem-api-create-files-store-locally-using-javascript-webkit.html这允许您通过浏览器从沙盒文件系统中保存和读取文件。

至于其他支持,它尚未被确认为HTML5规范集的补充。所以它只能用于镀铬。

您还可以使用所有现代浏览器都支持的IndexDB系统。

您可以在服务工作者中使用这两种服务来管理内容的加载和管理,但我不得不质疑您为什么要阻止自己更新index.html

答案 1 :(得分:4)

"安全javascript加载" / TOFU的设计目标通常与javascript加密和浏览器机密(例如Cyph,Mega)相关联,因此我将在此过程中包含一些相关的建议。 / p>

你处于危险的境地。有很多龙。

选项1:实施feross/infinite-app-cache以在浏览器中永久缓存应用

这是在所有浏览器中实现TOFU网络应用所需的最少代码。

的index.html:

<html manifest="manifest.appcache">

manifest.app cache:

CACHE MANIFEST
/manifest.appcache
/index.html
/script-loader.js

并确保您使用内容类型&#34; text / cache-manifest&#34;来提供清单。

注意:此标准已弃用,但浏览器停用此功能需要几年时间。

问题:如果攻击者(已经攻击过您的服务器)可以欺骗用户访问不在应用缓存中的网址,他们可以提供任意代码来提取/使用浏览器机密等。

解决方案:用户输入无法被同一域上的恶意网页截获(除非您做的事情非常愚蠢),因此使用用户提供的密码和dchest / scrypt-加密任何浏览器机密异步-JS。

要考虑的另一件事是页面的缓存内容可以通过使用AJAX由恶意页面提取 - 因此您必须使用用户输入,而不仅仅是呈现给页面的随机令牌。

选项2:使用HPKP自杀和服务工作者扩展上述解决方案

实施HPKP Suicide永久&#34;烘烤&#34;通过阻止用户与服务器的连接将应用程序放入浏览器中。

如果(并且仅当)您实施了HPKP自杀,服务工作者现在可以安全使用,因为如果浏览器无法重新下载服务工作者,则强制执行的最长24小时无效。

index.html或script-loader.js:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js').catch(function (error) {
      console.error(error);
    });
  });
}

服务worker.js:

var files = [ 
  '/',
  'index.html',
  'script-loader.js'
].map(file => new Request(file))

self.addEventListener('install', () => {  
  caches.open('cache')
    .then(cache => {
      files.map(file => {
        fetch(file)
          .then(response => cache.put(file, response))
          .catch(err => console.error(err))
      })
    })
    .catch(err => console.error(err))
})

self.addEventListener('fetch', (e) => {
  var url = e.request.url.split('#')[0]

  if (!files.filter(file => file.url === url).length) {
    return e.respondWith(new Response('Not Found', { status: 404 }))
  }

  return e.respondWith(
    caches.match(e.request).then(cachedResponse => {
      if (cachedResponse) return cachedResponse

      return Promise.all([
        caches.open('cache'),
        fetch(e.request.clone())
      ]).then((results) => {
        var cache = results[0]
        var response = results[1]

        cache.put(e.request, response.clone())

        return response
      })
    })
  )
})

重要提示:如果没有HPKP自杀,使用服务工作者比无限应用缓存更安全,因为服务工作者的最大年龄为24小时,即使您的服务器缓存也是如此指令设定了更高的年龄。使用服务工作者也将完全禁用应用程序缓存。如果您没有实施HPKP自杀,那么与服务工作者一起努力实现这一目标是浪费时间。

<强>讨论

  • HPKP自杀已经失去了Chrome的永久性保证,因为他们最近实施了60天的最大最大年龄(请参阅问题#523654进行讨论)
  • 我强烈建议您对所有浏览器加密使用TweetNaCl.js:错误地使用它需要花费精力,除非您要加密大文件,否则与WebCrypto的性能差异无关紧要

答案 2 :(得分:1)

您还可以使用Cache API,它可以保存您的请求的响应(各种请求 - html页面,api请求,图像)。但请注意,它目前仅支持Chrome和Firefox。

在该页面上也是如何将其与fetch

一起使用的示例