保护 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 = '在线体验仍可使用。'; });}明确的分支让安全性或能力检测失败可见,同时不阻塞页面。
通过响应头发送 CSP
链接到“通过响应头发送 CSP”一节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 脚本所在目录。若要请求超出该目录的作用域,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)。