specification.website部署与安全:Cloudflare Pages+Worker、严格CSP与零第三方脚本的隐私策略全记录
【免费下载链接】specification.websiteWebsite specification — HTML, accessibility, security, SEO, agent-readiness. Platform-agnostic, sourced, MIT.项目地址: https://gitcode.com/gh_mirrors/sp/specification.website
specification.website 是一个"好网站该做什么"的平台无关规范站点,它本身就是一个安全与隐私的活教材:静态 Astro 站点部署在 Cloudflare Pages 上,配 Pages Functions 做爬虫识别与内容协商,一个独立 Cloudflare Worker 提供 MCP 查询服务;全站启用严格 CSP(无unsafe-inline)、子资源完整性(SRI)哈希与零第三方脚本的隐私策略。本文完整记录这套部署与安全架构的落地方式。
一、部署架构:Cloudflare Pages + Functions + 独立 Worker
整个站点是纯静态构建(Astro 7 + Tailwind),推送main分支即由 Cloudflare Pages 的 Git 集成自动部署,没有任何手动发布流程。
三层架构各司其职:
| 层 | 位置 | 职责 |
|---|---|---|
| 静态资产 | dist/ | 由 Astro 构建,含 Pagefind 搜索索引 |
| Pages Functions | functions/ | 爬虫检测、Accept: text/markdown内容协商、Reporting API 收集 |
| 独立 Worker | mcp/ | 在mcp子域上提供 MCP/A2A 只读查询,随内容变更自动重新部署 |
关键配置都在 wrangler.toml 里:它声明了 Analytics Engine 数据集绑定(AGENT_LOG记录爬虫流量、REPORT_LOG记录浏览器策略报告)和 D1 数据库(WebSub 订阅存储),构建产物目录指向./dist。
一个容易被忽略的细节是 public/_routes.json:它把/_astro/*、/pagefind/*、/og/*等纯静态路径排除在 Functions 之外,确保爬虫日志只运行在 HTML 和 well-known 路径上,静态资源永远绕过 Worker,既省开销又保证缓存效率。
二、严格 CSP 落地:为什么全站没有一行未受控的内联脚本
站点的全站响应头定义在 public/_headers 中。其 CSP 的核心思路是:
script-src 'self'+ 4 个sha256哈希:全站仅有的几段内联脚本(暗色模式初始化、推测规则、import map、WebMCP 守卫)各自用固定哈希白名单放行,完全没有unsafe-inline。frame-ancestors 'none'+X-Frame-Options: DENY:双重防点击劫持。connect-src仅保留一个外部域名:自托管 Plausible 的事件上报端点,脚本本身来自'self'。object-src 'none'、base-uri 'self'、form-action 'self':堵住插件嵌入、<base>注入与表单外传。- 附加层:
Strict-Transport-Security(约 2 年)、Permissions-Policy全面禁用摄像头/麦克风/定位/interest-cohort等能力、Cross-Origin-Opener-Policy: same-origin。
配套规范页见 src/content/spec/security/content-security-policy.md,其中特别指出:孤立的unsafe-inline不是"弱兜底",而是整条策略——这正是本站拒绝它的原因。
三、子资源完整性(SRI):每个脚本都有密码学指纹
站点把 SRI 做到了三个层次:
- 构建期哈希:src/lib/integrity.ts 在构建时直接读取
public/下脚本的字节计算sha384哈希,页面中每个<script>都带integrity属性——哈希与实际分发的字节不可能漂移。 - 构建后守卫:Pagefind 的运行时是在 Astro 构建之后才生成的,无法在构建期哈希,于是由 scripts/check-integrity.mjs 在构建末尾校验所有手工固定的哈希字面量,不一致就直接让构建失败并打印可粘贴的正确值。
Integrity-Policy-Report-Only:全站第一个脚本都带 SRI 后,这条只报告不拦截的策略就成了"回归绊线"——任何无完整性脚本被发出都会触发报告,确认干净运行后即可切换为强制模式。
四、零第三方脚本的隐私策略:只留一个"伪装成自托管"的统计
隐私承诺(完整版本在 src/pages/privacy.astro)可以浓缩成四条:
- 无 Cookie、无 localStorage、无指纹识别。唯一的统计是 Plausible,且脚本自托管在 public/js/plausible.js——一个每日定时刷新的冻结副本,配合 SRI 哈希固定;CSP 的
script-src里因此根本没有plausible 的域名,只有事件上报端点留在connect-src。 - 不存 IP:Plausible 只保留页面 URL、来源、国家(由 IP 推导后丢弃 IP 本身)。
- 聚合日志同样脱敏:functions/reports.ts 收集浏览器的 Reporting API 上报(CSP 违规、弃用特性告警等),写入 Analytics Engine 供内部仪表板
/admin/stats(Cloudflare Access 门禁后)读取——无 IP、无 Cookie、无 URL 查询串,且"永不抛出、永不阻塞",日志失败也不会影响访客。 - 屏蔽即失效但无害:Plausible 请求被所有主流内容拦截器拦截,站点功能完全不受影响。
五、本地部署与验证步骤
想自己跑一遍这套架构,步骤如下:
克隆仓库:
git clone https://gitcode.com/gh_mirrors/sp/specification.website安装依赖并本地开发(Node ≥ 22.12,
predev会自动生成图标与 OG 图):npm install npm run dev # http://localhost:31337构建并跑完整性校验:
npm run build # astro build && pagefind && check-integrity部署:在 Cloudflare Pages 面板绑定仓库 Git 集成,
main分支自动构建;独立 Worker 手动执行cd mcp && npm run deploy(内容变更时由 GitHub Action 自动触发)。验证安全头:
curl -sI <站点首页> | grep -i content-security-policy应返回完整策略;DevTools 控制台出现Refused to load …即说明 CSP 正在拦截违规资源。
六、参考文件
- 部署绑定:wrangler.toml、mcp/wrangler.toml
- 响应头与 CSP:public/_headers
- 路由排除:public/_routes.json
- 完整性哈希:src/lib/integrity.ts、scripts/check-integrity.mjs
- 报告收集与爬虫检测:functions/reports.ts、functions/_shared/bot-detect.ts
- 隐私政策源文件:src/pages/privacy.astro
- CSP / SRI 规范页:src/content/spec/security/content-security-policy.md、src/content/spec/security/subresource-integrity.md
这套架构给新手的核心启示只有一条:安全策略不是配置项,而是构建流程的一部分——哈希由构建计算、违规由构建守卫拦截、隐私承诺由代码强制执行,站点才可能真正做到"所写即所行"。
【免费下载链接】specification.websiteWebsite specification — HTML, accessibility, security, SEO, agent-readiness. Platform-agnostic, sourced, MIT.项目地址: https://gitcode.com/gh_mirrors/sp/specification.website
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考