静态站点不需要 JavaScript 才能站得住脚;<script> 标签的缺席本身就可能是重点。本文论证一个在线内容站点通过策略关闭脚本通道的工程依据,并说明如何在公共边缘验证策略。下方头部来自仓库预期配置,不是刚刚观测到的生产响应。
论证分三部分:你删掉的攻击面;让删除可被观察的契约;以及不该关闭脚本能力的情况。
关闭脚本通道能缩小哪些威胁面
一个不执行自身或第三方脚本的页面,移除了原本需要修补与审查的客户端脚本依赖。有效的无脚本 CSP 会在合规浏览器中阻止注入脚本执行,但 HTML 注入仍可改变文字、链接与页面结构。跟踪还可能依赖图片、导航或服务器日志,无须 JavaScript。本站另有不依赖第三方浏览器资源的要求,这比删掉脚本标签更广。没有浏览器脚本包,就没有其依赖漂移;构建工具与服务器依赖仍然存在。每一类都是有限、可命名的表面——也就是"小系统"那种"选择你能说清的边界"的特性。
这不是声称站点"安全",而是声称攻击面更窄,并且关键的是更容易推理,因为它是靠构造枚举的,而不是靠审计枚举的。
让边界可强制执行的响应头
口味不是策略。这里的区别是,服务器下发策略,由浏览器强制执行。仓库中的 Caddy 示例配置指定:
content-security-policy: default-src 'self'; base-uri 'self'; form-action 'none'; frame-ancestors 'none'; object-src 'none'; script-src 'none'; style-src 'self'; img-src 'self' data:
其中 script-src 'none' 指令是可强制执行的部分。在这个完整策略且没有更具体的脚本放行规则时,合规浏览器会拒绝页面脚本、内联事件处理器与 JavaScript URL。若使用的是 Content-Security-Policy-Report-Only,则只报告、不阻止。以后添加 script-src-elem 或 script-src-attr 时需要重新审查,因为它们可覆盖各自脚本类别的回退规则。
构建校验器检查生成产物中的可执行脚本、事件处理器与 URL,不能证明反向代理确实发送了预期 CSP。应分别抓取代表性 HTML、错误页与重定向目的页,检查实际强制策略,并测试浏览器行为。源码检查、响应检查与浏览器执行是三项不同的验证。
移除之后静态结构带来的好处
没有脚本之后,内容模型回归到更接近已发布文档的东西。缓存处理的是 HTTP 表示,不是页面后来发生的 DOM 变化。静态产物让表示更容易检查和版本化;ETag 与新鲜度策略仍然取决于服务器配置。在终端里读线上 HTML、用"查看源代码"、或索引整棵树都很直接,因为产物就是磁盘上的普通文件。这是这个站点接受的交换:没有脚本管理的状态、没有客户端渲染、没有依赖 JavaScript 视图模型的反馈。原生链接、键盘导航、CSS 行为以及 details 之类的元素仍然可以提供交互。对文档与运维站点而言,这是正确的取舍,值得写下来。
什么时候"零 JS"的论断是错的
这是一层功能,不是一张纯净的标签。一个真正需要客户端交互的站点——实时仪表盘、文档编辑器、支付流程——不应该为了迁就约束就扭曲成提供静态 HTML 再硬塞变通方案。错误的应用是削足适履地把产品切成适应约束的形状。正确的应用是认识到:用来阅读、检索、归档的内容,从"成为文档"中收益;只有在文档本身不足时才需要脚本。
实际响应头是所采样响应的有用证据,却不能证明所有浏览器都支持、或每条路由都具有相同策略。仍须安全地渲染内容、保护发布权限、维护生成器与服务器。只有说清这些限制,边界才真正可辩护。
来源
W3C:Content Security Policy Level 3,策略下发、脚本指令与回退规则(工作草案),已核验 2026-10-15。
MDN:内容安全策略(
script-src),禁用脚本执行的指令,已核验 2026-10-15。PortSwigger:什么是跨站脚本(XSS)?,脚本注入及其后果,已核验 2026-10-15。
OWASP:内容安全策略,CSP 作为纵深防御控件,已核验 2026-10-15。