跳转到内容

保护 PWA

发布于 更新于

PWA 用安全上下文承载强大功能,用内容安全策略(CSP)约束资源加载,并用明确的 Service Worker 作用域控制请求范围。部署时分别配置并检查这些边界。用 window.isSecureContext 检查活动上下文,注册前再检测 navigator 中是否有 serviceWorker。页面可以用 ReportingObserver 观察 CSP 违规,也可以借助报告响应头和指令把报告发送到端点(Secure contexts,MDN;Content-Security-Policy,MDN)。

MDN 将 ServiceWorkerContainer.register() 描述为自 2018 年 4 月起已在各浏览器中广泛可用(ServiceWorkerContainer.register(),MDN)。MDN 把 CSP 响应头标为广泛可用,但具体指令的支持情况仍有差异(Content-Security-Policy,MDN)。

MDN 将 HTTPS 与 http://localhost 等本地开发来源列为可能可信的来源。当前文档不可信时,仅限安全上下文的功能不可用。生产环境把 HTTP 流量重定向至 HTTPS,并在启动需要安全上下文的功能前检查运行时属性。

回退路径保留导航和在线内容,同时跳过 Service Worker 注册。

const status = document.createElement('output');
status.id = 'offline-status';
status.setAttribute('aria-live', 'polite');
document.body.append(status);
if (!window.isSecureContext) {
status.textContent = '此连接无法使用离线安装。';
} else if (!('serviceWorker' in navigator)) {
status.textContent = '此浏览器使用在线体验。';
} else {
navigator.serviceWorker.register('/sw.js', { scope: '/' })
.then(() => { status.textContent = 'Service Worker 注册已创建或更新。'; })
.catch(() => { status.textContent = '在线体验仍可使用。'; });
}

明确的分支让安全性或能力检测失败可见,同时不阻塞页面。

Content-Security-Policy 响应头让网站限制脚本、样式、图片、frame 和连接等资源。MDN 的仅报告示例在测试期间使用 Content-Security-Policy-Report-Only,它会报告违规,但不会阻止代码执行。

Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'

此示例把默认加载与脚本限制为同源,阻止插件,限制 <base> URL,并阻止页面被嵌入。请按应用实际加载的资源调整策略。

注册的默认作用域是 Service Worker 脚本所在目录。若要请求超出该目录的作用域,Service Worker 脚本响应必须提供允许该范围的 Service-Worker-Allowed 头(ServiceWorkerContainer.register(),MDN;Service worker script response,W3C)。

如果 worker 只应控制 /app/,把脚本放在 /app/sw.js,并以 { scope: '/app/' } 注册。避免作用域重叠:MDN 提醒通常应避免重叠,因为只有一个注册会控制文档。

检查最终响应,而不只检查源文件。确认页面处于安全上下文、文档响应带有 CSP 头,并且 registration.scope 与预期 URL 边界一致。用 ReportingObserver 观察 CSP 违规,或按策略中的报告指令将报告发送到端点(Content-Security-Policy,MDN)。