我正在设计一个JavaScript安全加载器。加载器在index.html
中内联。安全加载器的目标是仅加载受信任的JavaScript资源。 index.html
的内容主要限于安全加载程序。出于安全考虑,我希望index.html
(存储在缓存中)永远不会更改,即使我的网站被黑客攻击。
如果服务器无法篡改缓存,我如何缓存index.html
?我想知道ServiceWorker
是否可以提供帮助。实际上,index.html
将注册一个服务工作者从不可变的缓存中获取自己(甚至没有网络请求)。
答案 0 :(得分:4)
,您可以使用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自杀,那么与服务工作者一起努力实现这一目标是浪费时间。
<强>讨论强>
答案 2 :(得分:1)
您还可以使用Cache API,它可以保存您的请求的响应(各种请求 - html页面,api请求,图像)。但请注意,它目前仅支持Chrome和Firefox。
在该页面上也是如何将其与fetch