guides/csp-static-sites.html

静态网站的 CSP

2026 年静态网站真正需要的 Content Security Policy 指令,加上来自 gautamkhorana.com 的 FAL + Supabase + Pagefind 方案。

静态网站的 CSP

← Blog All posts in this topic

CSP 的作用

Content Security Policy 是一个 HTTP 头部,告诉浏览器允许从哪些来源为你的页面加载资源。配置得当,它可以防止大多数 XSS、点击劫持和供应链攻击。配置不当,它会以难以诊断的方式无声地破坏功能。

静态网站往往对 CSP 文档记录不足,因为认为风险较低。现实是静态网站缺少 CSP 指令会破坏视频播放、图像加载、搜索功能或字体渲染,而浏览器控制台消息是唯一的信号。

按资源类型映射

控制每种资源类型的指令:

img-src 用于 img 标签。media-src 用于 video、audio、source 元素。frame-src 用于 iframe。connect-src 用于 fetch 和 WebSocket。script-src 用于 script 标签。style-src 用于 style 标签和 link rel=stylesheet。font-src 用于 @font-face。

关键:default-src "self" 不包括来自第三方主机的视频。如果忘记 media-src,来自 Supabase Storage 的视频将无法播放,只显示海报。检查浏览器控制台,它会显示阻止该内容的指令;当视频神秘无法播放时先检查这里。

2026 年 5 月事件

在 gautamkhorana.com 上,2026 年 5 月,一个托管在 Supabase Storage 上的 Kling MP4 文件正确渲染了 HTML,但从未播放。海报图像显示了,但视频无法启动。调试二十分钟后,问题是 CSP 没有 media-src 指令,浏览器正在静默阻止视频元素。

修复方式是在 netlify.toml 中添加一行:media-src "self" https://*.supabase.co。只有海报但无播放的症状是判断依据:这意味着 CSP 允许图像但不允许视频。

静态搜索库需要 wasm 和 worker 权限

Pagefind、Stork、Tinysearch 和其他静态站点搜索库使用 WebAssembly 和 Web Workers。如果 CSP 不包含 script-src "wasm-unsafe-eval" 和 worker-src "self" blob:,搜索将永远卡在"正在搜索...",控制台不会报错。

gautamkhorana.com 上的第二个事件,2026 年 5 月:搜索抽屉卡在"正在搜索...",因为当 wasm 被阻止时 pagefind.init() 静默失败了。修复方式是在 script-src 中添加 "wasm-unsafe-eval",在 worker-src 中添加 "self" blob:。

FAL + Supabase + Pagefind 站点的最小化 CSP

必需:

img-src self https://*.supabase.co https://*.fal.media,用于英雄图像和FAL生成的资源。media-src self https://*.supabase.co,用于视频。connect-src self https://*.supabase.co,用于Supabase API调用。script-src self "wasm-unsafe-eval",用于Pagefind。worker-src self blob:,用于Pagefind workers。style-src self "unsafe-inline",用于Astro作用域样式。font-src self,用于自托管字体。

每当你添加新的资源主机(Cloudinary、Bunny、R2或其他),审查netlify.toml或vercel.json,并将该主机添加到该资源类型可能使用的每条指令中。搞错的代价是一个在生产环境中才显露的无声破损。

测试CSP更改

CSP-Report-Only模式让你在生产环境中测试策略更改而不会破坏任何内容。浏览器会将可能的违规记录到报告端点而不是阻止请求。新指令在仅报告模式下运行一周,审查违规情况,然后升级为强制执行。

大多数CSP失败在生产环境中是无声的。报告端点是了解你实际破损了什么的唯一方式。在发布任何非平凡的CSP更改之前建立一个。

WHEN YOU ARE READY TO TALK