DevToolBox免费
博客

内容安全策略 (CSP) 完全指南:从基础到生产部署

12 分钟阅读作者 DevToolBox

内容安全策略 (CSP) 是防御跨站脚本 (XSS) 攻击最有效的手段之一。通过告诉浏览器哪些资源可以加载,CSP 即使在应用存在漏洞时也能阻止恶意代码注入。

什么是 CSP,为什么重要?

CSP 是一个 HTTP 响应头,控制浏览器可以为给定页面加载哪些资源。没有 CSP,一个 XSS 漏洞就可能让攻击者注入脚本、窃取 Cookie、重定向用户或篡改网站。

CSP 工作原理

当浏览器收到 CSP 头时,会通过阻止违规资源来执行策略:

Browser receives HTTP response:
  Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com

Browser allows:
  ✅ <script src="/app.js">              (same origin = 'self')
  ✅ <script src="https://cdn.example.com/lib.js">

Browser blocks:
  ❌ <script src="https://evil.com/steal.js">
  ❌ <script>alert('XSS')</script>       (inline = not allowed)

所有 CSP 指令

指令控制示例
default-srcFallback for all resource types'self'
script-srcJavaScript files and inline scripts'self' https://cdn.example.com
style-srcCSS stylesheets and inline styles'self' 'unsafe-inline'
img-srcImages (img, favicon, CSS background)'self' data: https:
font-srcWeb fonts (@font-face)'self' https://fonts.gstatic.com
connect-srcXHR, fetch, WebSocket, EventSource'self' https://api.example.com
media-srcAudio and video elements'self'
frame-srcIframes and embedded frames'self' https://www.youtube.com
object-srcPlugins (Flash, Java applets)'none'
base-uriBase element URLs'self'
form-actionForm submission targets'self'
frame-ancestorsWho can embed this page (anti-clickjacking)'self'
upgrade-insecure-requestsUpgrade HTTP requests to HTTPS(no value needed)

来源值说明

来源含义
'self'Same origin (protocol + host + port)
'none'Block all resources of this type
'unsafe-inline'Allow inline scripts/styles (reduces security!)
'unsafe-eval'Allow eval(), Function(), setTimeout(string)
'strict-dynamic'Trust scripts loaded by already-trusted scripts
'nonce-abc123'Allow specific inline script with matching nonce attribute
'sha256-...'Allow inline script matching this hash
https:Allow any HTTPS resource
data:Allow data: URIs (e.g., inline images)
blob:Allow blob: URIs
*.example.comAllow all subdomains of example.com

分步实施

步骤 1:从仅报告模式开始

先以仅报告模式部署 CSP,在不破坏网站的情况下识别违规:

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

步骤 3:构建策略

根据分析结果创建策略。从严格开始,按需放宽:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.example.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'self';
  base-uri 'self';
  form-action 'self';
  object-src 'none';
  upgrade-insecure-requests

常见 CSP 配置

严格策略(最高安全性)

Content-Security-Policy:
  default-src 'none';
  script-src 'self';
  style-src 'self';
  img-src 'self';
  font-src 'self';
  connect-src 'self';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'none';
  object-src 'none';
  upgrade-insecure-requests

中等(典型 SPA)

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'unsafe-inline' 'unsafe-eval';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: blob: https:;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com wss://ws.example.com;
  frame-ancestors 'self'

带 Google Analytics

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com;
  img-src 'self' https://www.google-analytics.com https://www.googletagmanager.com;
  connect-src 'self' https://www.google-analytics.com https://analytics.google.com

实现方法

Nginx

add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;

Apache

Header set Content-Security-Policy "default-src 'self'; script-src 'self'"

Express.js

// Using helmet middleware (recommended)
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "https://cdn.example.com"],
    styleSrc: ["'self'", "'unsafe-inline'"],
    imgSrc: ["'self'", "data:", "https:"],
  }
}));

// Or manually
app.use((req, res, next) => {
  res.setHeader('Content-Security-Policy',
    "default-src 'self'; script-src 'self'");
  next();
});

HTML Meta 标签

<meta http-equiv="Content-Security-Policy"
  content="default-src 'self'; script-src 'self'">

常见 CSP 错误

错误影响修复
脚本使用 unsafe-inline破坏 XSS 防护改用 nonce 或 hash
使用 unsafe-eval允许 eval() 等函数重构代码避免 eval()
script-src 使用通配符 (*)允许任何域的脚本白名单指定域名
忘记处理内联样式阻止 CSS-in-JS 库style-src 添加 unsafe-inline 或使用 nonce
未先在仅报告模式测试破坏网站功能始终先从仅报告模式开始
缺少 base-uri 指令允许 base 标签注入添加 base-uri 'self'

常见问题

CSP 能防止哪些攻击?

CSP 主要通过控制脚本执行来防止 XSS 攻击。还能防止点击劫持(frame-ancestors)、数据注入和混合内容问题。

CSP 能替代输入验证吗?

不能。CSP 是深度防御措施。仍需验证和清理所有用户输入。CSP 是其他防御失败时的安全网。

如何在内联脚本中使用 CSP?

使用 nonce(添加到 CSP 头和 script 标签的随机令牌)或 hash(脚本内容的 SHA-256)。避免使用 unsafe-inline。

CSP 会拖慢网站吗?

不会。CSP 由浏览器执行,性能影响可以忽略。头本身很小。唯一的开销是生成 nonce(如果使用的话),这也是极小的。

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

🛡️CSP Header Generator.ht.htaccess GeneratorNXNginx Config Generator🏷️Meta Tag Generator

相关文章

Docker Compose 速查表:服务、卷和网络

Docker Compose 核心参考:服务定义、卷挂载、网络配置、环境变量和常见栈示例。

CORS 跨域错误完全解决指南

逐步解决 CORS 错误。涵盖 Access-Control-Allow-Origin、预检请求、凭证以及 Express、Django、Nginx 等服务器配置。