ToolPal
锁和安全概念图

CSP 生成器:告别手写 Content Security Policy 头的痛苦

📷 Pixabay / Pexels

CSP 生成器:告别手写 Content Security Policy 头的痛苦

Content Security Policy 保护网站免受 XSS 攻击。学习指令配置、常见错误和如何在不破坏网站的情况下测试 CSP。

D作者: Daniel Park2026年4月14日4分钟阅读

Content Security Policy(CSP)是防御 XSS 攻击最有效的工具之一,但同时也是配置最令人头痛的 HTTP 头之一。CSP 头的语法复杂,一个指令名拼错了不会报错,而一个遗漏的指令可能就是安全漏洞或者把整个网站搞崩的原因。

这篇文章会系统讲解 CSP 的工作原理、核心指令的用法、常见陷阱,以及如何用 CSP 生成器 准确高效地生成 CSP 配置。

为什么 CSP 重要

XSS(跨站脚本攻击)长期以来是 OWASP Top 10 最危险漏洞之一。攻击者通过在网页中注入恶意 JavaScript,可以:

  • 窃取用户的 session token 和 Cookie
  • 代替用户发起请求(CSRF)
  • 在页面中插入假冒的登录表单
  • 读取页面上的敏感信息

输入验证是第一道防线,但实际情况往往是复杂的:富文本编辑器、第三方内容、遗留代码……总有漏网之鱼。CSP 是第二道防线——即使 XSS 注入成功了,CSP 也能阻止恶意脚本的执行。

CSP 的基本结构

CSP 通过 HTTP 响应头发送:

Content-Security-Policy: 指令1 值1 值2; 指令2 值1; ...

举个例子:

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data: https:;

每个指令用分号分隔,指令名后跟一个或多个允许的来源,用空格分开。

核心 CSP 指令详解

default-src:兜底指令

其他未明确指定的资源类型会回退到 default-src

default-src 'self';

'self' 表示只允许同源(相同协议+域名+端口)的资源。

script-src:最重要的指令

控制 JavaScript 的加载来源,是 CSP 中最关键的指令:

script-src 'self' https://cdn.jsdelivr.net https://www.googletagmanager.com;

常用来源值:

  • 'self' — 只允许同源脚本
  • 'none' — 禁止所有脚本
  • 'nonce-随机值' — 只允许带有匹配 nonce 属性的内联脚本
  • 'strict-dynamic' — 允许已信任的脚本动态加载其他脚本
  • https://example.com — 允许指定来源

生产环境绝对避免'unsafe-inline''unsafe-eval'。这两个值会大幅削弱 CSP 的防护效果。

style-src:控制样式来源

style-src 'self' https://fonts.googleapis.com;

img-src:控制图片来源

img-src 'self' data: https:;

data: 允许 base64 内联图片,https: 允许所有 HTTPS 来源的外部图片。

font-src:控制字体来源

font-src 'self' https://fonts.gstatic.com;

connect-src:控制 Ajax 和 WebSocket

控制 fetch()XMLHttpRequest、WebSocket 等的目标地址:

connect-src 'self' https://api.example.com wss://realtime.example.com;

frame-src:控制 iframe

frame-src 'none';            /* 禁止所有 iframe */
frame-src https://www.youtube.com;  /* 只允许 YouTube */

form-action:控制表单提交目标

form-action 'self';

base-uri:限制 base 标签

防止攻击者插入 <base> 标签来劫持相对 URL:

base-uri 'self';

upgrade-insecure-requests:强制 HTTPS

自动将页面上的 HTTP 请求升级为 HTTPS:

upgrade-insecure-requests;

常见的配置陷阱

陷阱一:用 unsafe-inline 图省事

为了让内联脚本正常运行而加上 'unsafe-inline' 是最常见的错误,这基本上让 script-src 的防护形同虚设。

正确做法:使用 nonce。服务器每次请求生成一个随机字符串,只有带有匹配 nonce 的 script 标签才被允许执行:

<!-- 服务器端渲染时注入 nonce -->
<script nonce="aB3kR9mX2qL7">
  // 这个脚本会被允许执行
</script>

CSP 头:

script-src 'self' 'nonce-aB3kR9mX2qL7';

由于 nonce 每次请求都不同,攻击者无法预测,因此无法利用这个通道注入脚本。

陷阱二:忘记第三方脚本

Google Analytics、Stripe、Intercom、Hotjar 等第三方服务需要从各自的 CDN 加载脚本,必须加入 script-src 白名单:

script-src 'self'
  https://www.googletagmanager.com
  https://www.google-analytics.com
  https://js.stripe.com
  https://widget.intercom.io;

部署 CSP 前,建议在浏览器控制台检查是否有资源被意外阻止。

陷阱三:connect-src 和 img-src 遗漏

Google Analytics 不只需要 script-src,它还需要:

  • img-src 允许跟踪像素
  • connect-src 允许数据上报请求
script-src  'self' https://www.googletagmanager.com;
img-src     'self' https://www.google-analytics.com data:;
connect-src 'self' https://www.google-analytics.com;

陷阱四:不测试直接上线

直接把 CSP 推到生产环境很危险——一个漏掉的来源可能导致 JavaScript 报错、样式丢失或 API 请求失败。

report-only 模式:安全测试的利器

在正式应用 CSP 之前,先用 Content-Security-Policy-Report-Only 头测试:

Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-violations

这个头的作用:

  • 违规不会阻止任何内容的加载(网站照常工作)
  • 所有违规都会被上报到 report-uri 指定的地址
  • 你可以在生产流量中收集数据,找出需要白名单的资源

违规报告是 JSON 格式:

{
  "csp-report": {
    "document-uri": "https://example.com/page",
    "violated-directive": "script-src-elem",
    "blocked-uri": "https://external.example.com/script.js",
    "original-policy": "default-src 'self'; script-src 'self'"
  }
}

根据报告逐步完善白名单,直到没有误报,再切换到正式的 Content-Security-Policy 头。

实际配置示例

静态展示网站

Content-Security-Policy:
  default-src 'self';
  img-src 'self' data: https:;
  style-src 'self';
  font-src 'self';
  form-action 'self';
  base-uri 'self';
  frame-ancestors 'none';

使用 Google Analytics 的营销网站

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com;
  style-src 'self' https://fonts.googleapis.com;
  font-src 'self' https://fonts.gstatic.com;
  img-src 'self' https://www.google-analytics.com data:;
  connect-src 'self' https://www.google-analytics.com;
  form-action 'self';
  base-uri 'self';

带 Stripe 支付的 SaaS 产品

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://js.stripe.com;
  style-src 'self' https://fonts.googleapis.com;
  font-src 'self' https://fonts.gstatic.com;
  img-src 'self' data: https:;
  connect-src 'self' https://api.stripe.com https://api.yourapp.com;
  frame-src https://js.stripe.com;
  form-action 'self';
  base-uri 'self';
  upgrade-insecure-requests;

使用 nonce 的 SPA 应用

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{服务器生成的随机值}' 'strict-dynamic';
  style-src 'self' 'nonce-{服务器生成的随机值}';
  img-src 'self' data: blob:;
  connect-src 'self' https://api.yourapp.com;
  font-src 'self';
  form-action 'self';
  base-uri 'self';
  upgrade-insecure-requests;

用 meta 标签设置 CSP

如果没有服务器端控制权(如纯静态托管),可以用 HTML meta 标签设置 CSP:

<head>
  <!-- 尽量放在 head 最前面 -->
  <meta http-equiv="Content-Security-Policy"
        content="default-src 'self'; script-src 'self'; style-src 'self'">
</head>

注意 meta 标签的限制:

  • 不支持 frame-ancestors 指令
  • 不支持 report-uri 指令
  • 比 HTTP 头稍晚生效(页面开始解析后才生效)

优先使用服务器端 HTTP 头,meta 标签作为备选。

推荐实施流程

  1. 先用 report-only 头 — 不阻止内容,只收集违规数据
  2. 收集几天的违规报告 — 覆盖真实用户的使用场景
  3. 分析报告,补充白名单 — 区分合法资源和真正的安全威胁
  4. 切换到正式 CSP 头 — 数据充分后再强制执行
  5. 持续监控 — 新功能上线后检查是否引入了新的违规

为什么用生成器

CSP 头的手写难点在于:

  • 指令名称多(十几个),记不全
  • 来源语法有细节('self' 需要引号,https: 不需要,data: 不需要,'nonce-xxx' 需要引号)
  • 漏掉某个指令不会有错误提示,只会在浏览器控制台看到被拦截的资源
  • 多个第三方服务的白名单管理越来越复杂

CSP 生成器 的优势:

  • 可视化界面选择指令和来源
  • 自动处理语法细节(引号、分号等)
  • 内置常见第三方服务(Google Analytics、Stripe、Cloudflare 等)的预设
  • 一键生成完整的 HTTP 头字符串,直接粘贴到服务器配置

总结

CSP 是现代 Web 安全体系中不可缺少的一环,正确配置可以大幅降低 XSS 攻击的危害。

核心要点:

  • 避免 'unsafe-inline''unsafe-eval',用 nonce 代替
  • 先用 report-only 模式在生产环境测试
  • 不要忘记第三方服务需要的所有指令(script-src、connect-src、img-src 等都可能需要配置)
  • base-uri 'self'form-action 'self' 防御其他类型的注入
  • 持续监控 CSP 违规报告

打开 CSP 生成器,一步步配置你需要的指令,生成正确的 CSP 头字符串,然后复制粘贴到你的服务器配置中——这比手写快多了,也可靠多了。

常见问题

D

关于作者

Daniel Park

Senior frontend engineer based in Seoul. Seven years of experience building web applications at Korean SaaS companies, with a focus on developer tooling, web performance, and privacy-first architecture. Open-source contributor to the JavaScript ecosystem and founder of ToolPal.

了解更多

分享文章

XLinkedIn

相关文章