第三方域是 PWA 的安全模型问题,而不只是技术约束
你的 PWA 安全边界决定了你可以构建什么、在哪里安装以及用户如何信任你。
为什么安全模型对可安装 web 应用很重要
PWA 不仅仅是一个可以离线工作的网站——它是一个安全边界。当用户安装 web 应用时,浏览器会授予它增强的功能:service workers、持久存储、后台同步、推送通知,有时甚至包括文件系统访问。这些功能按域划分,而这个作用域决定了哪些第三方集成是安全的、有风险的或不可能的。
理解此模型可以阻止阻碍安装或破坏用户信任的架构错误。
PWA 安全边界
每个 PWA 都受到其原始域的约束:
- 原始域 = 协议 + 主机名 + 端口(
https://example.com:443) - Service workers 仅控制其作用域(原始域 + 路径)内的请求
- 存储 API(
localStorage、IndexedDB、caches)是原始域隔离的 - 可安装性需要 HTTPS + 注册的 service worker
- 平台功能按原始域而不是项目授予
这种隔离是一种功能,而不是错误。这意味着你安装的 PWA 不会意外劫持其他站点的资源,其他站点也不能劫持你 PWA 的资源。
第三方集成模式及其风险
模式 1:Iframe 嵌入
<iframe src="https://thirdparty.com/widget"></iframe>- 安全性:同源策略适用。iframe 有自己的原始域。
- PWA 影响:Service worker 不控制 iframe 请求。iframe 缓存需要第三方自己的 service worker。
- 可安装性:iframes 不影响可安装性,但 iframe 资源无法利用你 PWA 的离线能力。
模式 2:跨域 API 调用
fetch('https://api.thirdparty.com/data', {
credentials: 'include'
})- 安全性:CORS 适用。第三方必须显式允许你的原始域。
- PWA 影响:如果 CORS 允许,你的 service worker 可以拦截并缓存这些请求。
- 可安装性:不直接影响可安装性,但 CORS 失败会破坏应用功能。
模式 3:第三方 cookie(越来越有风险的模式)
// 由 thirdparty.com 设置的身份验证 cookie
document.cookie = 'session=xyz; domain=thirdparty.com';- 安全性:现代浏览器默认阻止第三方 cookie(ITP、ETP)。
- PWA 影响:依赖第三方 cookie 的身份验证工作流对你的安装用户将失败。
- 可安装性:本身不是可安装性问题,但安装后身份验证失败会破坏用户信任。
模式 4:子域架构
https://app.example.com/ (PWA 作用域)
https://api.example.com/ (后端)
https://cdn.example.com/ (资产)- 安全性:子域是不同的原始域。Service worker 作用域必须显式包含它们。
- PWA 影响:可安装需要在根目录注册 service worker。子域资源需要仔细的作用域配置。
- 可安装性:多原始域架构需要作用域规划。Service worker 配置错误会阻止安装。
PWA 的实用安全检查清单
在声明你的应用可安装之前,验证:
- [ ] 所有关键资产(图标、图片、字体)托管在你的原始域或可靠的 CDN 下
- [ ] 第三方 API 使用 CORS,而不是基于 cookie 的身份验证
- [ ] Service worker 作用域覆盖用户可能导航到的所有路由
- [ ] 没有依赖你的 service worker 缓存策略的 iframe 依赖功能
- [ ] 身份验证使用第一方 cookie 或基于令牌的身份验证(JWT),而不是第三方 cookie
- [ ] CSP 标头允许你的原始域并阻止不必要的第三方脚本
第三方域何时是必要的(以及如何处理)
用例:嵌入第三方 widget(地图、支付、视频)
策略:Iframe + 第三方 service worker
如果第三方提供自己的 PWA 就绪 widget,他们的 service worker 处理 iframe 内的离线缓存。你的 service worker 在这里无能为力。
示例:嵌入地图 widget<iframe src="https://maps-provider.com/widget?callback=yourapp"></iframe>风险:Widget 可能无法离线加载。显示回退 UI。
用例:跨域 API
策略:CORS + 请求拦截
配置你的 service worker 缓存 API 响应:// service-worker.js
self.addEventListener('fetch', (event) => {
if (event.request.url.includes('https://api.example.com/')) {
event.respondWith(
caches.open('api-cache').then(cache =>
cache.match(event.request).then(response =>
response || fetch(event.request).then(networkResponse => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
})
)
)
);
}
});用例:多租户或多品牌应用
策略:子域 + 作用域 service workers
每个租户获得自己的子域(tenant1.app.com、tenant2.app.com),具有显式的 service worker 作用域。这隔离了每个租户的存储和缓存。安全审计框架
| 威胁 | 在 PWA 中的表现 | 缓解措施 | |--------|----------------|------------| | 跨站脚本攻击 (XSS) | 注入到你的 PWA 原始域的第三方脚本 | CSP 标头、Content-Security-Policy-Report-Only、脚本完整性检查 | | 跨站请求伪造 (CSRF) | 对第三方 API 的经过身份验证的请求,无 CORS 验证 | CSRF 令牌、SameSite cookie 属性、Origin 标头检查 | | 通过 iframes 的数据泄漏 | 第三方 iframes 读取你的 PWA 的 DOM | Iframe 沙箱属性、X-Frame-Options 标头 | | 存储分区 | 由于浏览器跟踪保护,第三方存储意外清除 | 使用第一方存储,避免第三方 cookie 进行持久化 |
这对开发者意味着什么
- 架构优先:在编写功能之前设计你的原始域结构。子域与单一原始域影响 service worker 配置。
- 安全即功能:关于安全模型的明确沟通建立用户信任。“你的数据保留在浏览器中。我们永远不会看到它”是一个信任信号。
- 为后 PC-3RD-COOKIE 时代规划:第三方 cookie 对 PWA 实际上已死。现在迁移到基于令牌的身份验证或第一方 cookie 身份验证。
这如何影响可安装性和平台功能
| 平台功能 | 安全要求 | 什么违反了它 | |---------------------|---------------------|------------------| | Service worker 注册 | HTTPS + 同源脚本 | HTTP 原始域、混合内容 | | 持久存储 | 原始域隔离存储 API | 用于持久化的第三方 cookie | | 后台同步 | Service worker 作用域控制 | 不在作用域内的子域资源访问 | | 推送通知 | VAPID 密钥 + 原始域关联 | 跨原始域共享 VAPID 密钥 | | 文件系统访问 | HTTPS + 显式用户手势 | 文件对话框中的原始域不匹配 |
决策框架:第三方与第一方架构
| 标准 | 保留第三方 | 迁移到第一方 | |-----------|----------------|------------------------| | 身份验证复杂性 | | ✓(对于关键流程) | | 需要离线缓存 | ✓ | ✓(你的 service worker) | | 用户对安全性的感知 | | ✓(第一方看起来更值得信任) | | 开发速度 | ✓ | | | 长期维护 | | ✓(第三方合同、弃用) |
迁移建议:对于身份验证和核心数据 API,构建或托管第一方端点。对于非关键 widget 和分析,具有沙盒化 iframe 的第三方集成是可以接受的。
来源
- Service Worker API - Same-origin policy
- CORS - HTTP access control
- Content Security Policy
- Chrome Site Isolation
- Safari ITP and Third-party Cookies
下一步
审核你的 PWA 的第三方依赖:
- 列出所有跨域 iframes 和 API 调用
- 识别哪些是安全关键的(身份验证、用户数据)
- 规划第三方 cookie 依赖的迁移路径
- 测试所有关键用户流的离线行为
你的 PWA 安全模型是它与用户和平台的契约。违反该契约会阻止安装并破坏信任。