CSP 内容安全策略
Content Security Policy(CSP,内容安全策略)是 HTTP 安全头中最重要的一个,它通过白名单机制控制页面可以加载哪些资源、执行哪些脚本,从根源上防御 XSS 攻击。本节将详细介绍 CSP header 的配置方法、常用指令(default-src、script-src、style-src)、report-uri 报告机制。
前置知识
阅读本节前,建议先了解:XSS 防护
CSP 概述
CSP 通过指定哪些来源的资源可以被加载,有效防止 XSS 和数据注入攻击:
Content-Security-Policy: 指令 值; 指令 值;基本指令
default-src
default-src 是所有资源类型指令的默认回退:
Content-Security-Policy: default-src 'self'| 源值 | 说明 |
|---|---|
'self' | 仅允许同源资源 |
'none' | 禁止所有来源 |
https: | 允许所有 HTTPS 资源 |
data: | 允许 data: URI |
blob: | 允许 blob: URI |
*.example.com | 允许指定域名的子域名 |
常用指令
| 指令 | 控制资源 |
|---|---|
default-src | 默认(所有类型) |
script-src | JavaScript |
style-src | CSS 样式 |
img-src | 图片 |
font-src | 字体 |
connect-src | AJAX/WebSocket |
media-src | 音频/视频 |
frame-src | iframe |
object-src | 插件(Flash 等) |
manifest-src | Web App Manifest |
worker-src | Web Worker |
base-uri | <base> 标签 |
form-action | 表单提交目标 |
配置示例
严格策略
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data:;
font-src 'self';
connect-src 'self';
frame-ancestors 'none';
base-uri 'self';
form-action 'self';允许 CDN
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' https://cdn.example.com;
img-src 'self' https://cdn.example.com data:;
font-src 'self' https://fonts.googleapis.com https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;使用 nonce
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>CSP nonce 示例</title>
<!-- 使用 nonce 允许内联脚本 -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'nonce-a1b2c3d4';
style-src 'self' 'unsafe-inline';
">
</head>
<body>
<!-- 使用 nonce 的内联脚本 -->
<script nonce="a1b2c3d4">
// 这个脚本被 CSP 允许
console.log('Hello from CSP!');
</script>
<!-- 外部脚本 -->
<script src="https://cdn.example.com/lib.js" nonce="a1b2c3d4"></script>
</body>
</html>使用 hash
<!-- 使用 hash 允许特定脚本 -->
Content-Security-Policy:
script-src 'self' 'sha256-base64-encoded-hash'
<!-- hash 值通过以下命令生成 -->
<!-- echo -n "console.log('hello')" | openssl dgst -sha256 -binary | openssl base64 -->report-uri 和 report-to
report-uri(已弃用但仍广泛支持)
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example.com;
report-uri /csp-violation-report-endpoint/;report-to(新标准)
Content-Security-Policy:
default-src 'self';
script-src 'self';
report-to csp-violations;
Report-To: {
"group": "csp-violations",
"max_age": 31536000,
"endpoints": [
{ "url": "https://report.example.com/csp-reports" }
]
}报告模式(仅报告)
使用 Content-Security-Policy-Report-Only 在不阻止违规的情况下收集报告:
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' https: 'unsafe-inline' 'unsafe-eval';
report-uri /csp-report;渐进式部署
建议先使用 Report-Only 模式运行一段时间,确认无误后再切换到正式 CSP。
报告处理
html
<!-- 服务器端接收 CSP 报告 -->
<!-- POST /csp-report -->
<!-- 报告格式为 JSON -->
<!--
{
"csp-report": {
"document-uri": "https://example.com/page.html",
"violated-directive": "script-src 'self'",
"blocked-uri": "https://evil.com/malicious.js",
"source-file": "https://example.com/page.html",
"line-number": 42,
"column-number": 15
}
}
-->注意事项
- 从宽松策略开始:先使用 Report-Only 模式测试
- 'unsafe-inline' 和 'unsafe-eval' 应避免:它们削弱了 CSP 的防护
- nonce 每次请求都应不同:防止 nonce 被重放攻击
- CSP 不替代输入验证:CSP 是纵深防御的一部分
- 考虑第三方脚本:CDN、分析工具、广告等都需要在 CSP 中声明
最佳实践
- 配置 Content-Security-Policy HTTP 头
- 避免使用 'unsafe-inline' 和 'unsafe-eval'
- 使用 nonce 或 hash 允许特定内联脚本
- 先用 Report-Only 模式测试
- 设置 frame-ancestors 'none' 防止点击劫持
- 定期审查 CSP 报告
- 设置合理的升级策略
下一节
继续学习:iframe 安全