Content-Security-Policy
Content-Security-Policy(CSP,内容安全策略)是一个强大的HTTP响应头,通过白名单机制精确控制浏览器可加载和执行的资源(如脚本、样式、图片等),从根本上防御跨站脚本(XSS)、点击劫持、数据注入等代码执行类攻击。其核心思想是“仅允许加载明确授权的资源”,替代了传统依赖“检测恶意内容”的被动防御模式。
一、CSP的核心机制:白名单控制
CSP通过一系列指令(Directives) 定义“允许加载的资源类型”和“资源来源”,浏览器严格按照指令执行,拒绝任何未授权的资源加载或代码执行。
1. 核心指令:控制资源加载范围
CSP的指令按“资源类型”分类,每个指令指定该类型资源的合法来源(白名单)。以下是常用核心指令:
| 指令 | 作用(控制哪种资源) | 示例值(合法来源) |
|---|---|---|
default-src |
所有资源的默认来源(未单独指定的资源继承此规则) | 'self' https://cdn.example.com(仅允许自身域名和指定CDN) |
script-src |
JavaScript脚本(最关键,防御XSS的核心) | 'self' 'unsafe-inline'(允许自身域名脚本和内联脚本,不推荐'unsafe-inline') |
style-src |
CSS样式表 | 'self' https://fonts.googleapis.com(允许自身和Google字体的样式) |
img-src |
图片资源(<img>、背景图等) |
'self' data: https://*.example.com(允许自身、data URI和example子域的图片) |
connect-src |
网络请求(XMLHttpRequest、Fetch、WebSocket等) | 'self' https://api.example.com(仅允许自身和指定API域名的请求) |
font-src |
字体资源 | 'self' https://fonts.gstatic.com(允许自身和Google字体的字体文件) |
object-src |
插件资源(<object>、<embed>、<applet>) |
'none'(禁止所有插件,现代网站几乎不用) |
frame-src |
嵌套框架(<iframe>、<frame>) |
'self' https://trusted.com(仅允许自身和可信域名的框架) |
media-src |
音视频资源(<audio>、<video>) |
'self' https://stream.example.com(允许自身和指定流媒体域名) |
manifest-src |
Web应用清单(manifest文件) | 'self' |
worker-src |
Web Worker 或 Service Worker 脚本的来源 | 'self' https://stream.example.com (允许自身和指定域名) |
2. 指令值:定义“合法来源”的格式
每个指令的取值(合法来源)支持多种格式,覆盖不同场景:
| 类型 | 示例 | 说明 |
|---|---|---|
| 关键字 | 'self' |
允许与当前页面同源(协议+域名+端口完全一致)的资源 |
'none' |
禁止所有来源(优先级高于其他值) | |
'unsafe-inline' |
允许内联脚本/样式(如<script>代码</script>、onclick事件),有安全风险(可能被XSS利用) |
|
'unsafe-eval' |
允许动态代码执行(如eval()、new Function()),有安全风险 |
|
'strict-dynamic' |
允许由已信任脚本动态生成的脚本(配合nonce/哈希使用,增强灵活性) | |
| 域名/URL | https://example.com |
允许指定域名的资源(精确匹配) |
https://*.example.com |
允许example.com的所有子域名(通配符*匹配任意子域) |
|
*.example.com |
允许example.com的所有子域(包括二级、三级子域),但不包括example.com本身 | |
| 协议 | data: |
允许data URI(如data:image/png;base64,...) |
https: |
允许所有HTTPS协议的资源(不限制域名) | |
| 哈希值 | 'sha256-abc123...' |
允许内容哈希匹配的内联脚本/样式(替代'unsafe-inline',更安全) |
| 随机数(nonce) | 'nonce-随机字符串' |
允许带指定nonce属性的内联脚本/样式(每次请求生成随机值,防御重放攻击) |
示例:一个严格的CSP策略
Content-Security-Policy:
default-src 'self'; # 默认仅允许同源资源
script-src 'self' https://trusted-cdn.com 'nonce-67890' 'sha256-abc123...'; # 脚本仅允许同源、可信CDN、指定nonce和哈希的内联脚本
style-src 'self' 'unsafe-inline'; # 样式允许同源和内联(暂时无法避免内联时使用)
img-src 'self' data: https://*.example.com; # 图片允许同源、data URI和example子域
connect-src 'self' https://api.example.com; # API请求仅允许同源和指定API域名
object-src 'none'; # 禁止所有插件
frame-src 'self'; # 仅允许同源框架
upgrade-insecure-requests; # 自动将HTTP请求升级为HTTPS
report-uri /csp-report-endpoint; # 违规报告发送到指定端点
二、特殊机制:增强安全性的关键指令
除了基础资源控制,CSP还包含多个特殊指令,用于解决特定安全问题:
1. 防御内联脚本/样式:nonce与哈希
内联脚本(如<script>alert(1)</script>)和内联事件(如onclick="...")是XSS攻击的主要载体。CSP默认禁止内联代码(除非用'unsafe-inline',但风险高),推荐用nonce或哈希实现安全的内联代码允许:
-
nonce机制:
服务器每次响应生成随机字符串(nonce),在CSP中声明并在 inline 脚本标签中添加nonce属性,仅匹配的内联脚本允许执行。
示例:# 响应头 Content-Security-Policy: script-src 'nonce-8f4d8a2b7c3e' 'self'<!-- 页面中的内联脚本(仅带正确nonce的允许执行) --> <script nonce="8f4d8a2b7c3e"> console.log("安全的内联脚本"); </script> -
哈希机制:
计算内联脚本/样式的哈希值(SHA-256、SHA-384、SHA-512),在CSP中声明,仅哈希匹配的内联代码允许执行。
示例:# 响应头(内联脚本"console.log('safe')"的SHA-256哈希) Content-Security-Policy: script-src 'sha256-abc123...' 'self'<!-- 哈希匹配,允许执行 --> <script>console.log('safe')</script>
2. 沙箱模式(sandbox)
sandbox指令为页面启用沙箱限制,模拟<iframe sandbox>的效果,限制页面的权限(如禁止表单提交、脚本执行、弹出窗口等)。常用于防御不可信内容(如用户生成的HTML、第三方嵌入内容)。
示例:
# 限制页面不可执行脚本、不可提交表单、不可导航到其他页面
Content-Security-Policy: sandbox allow-same-origin;
allow-same-origin:允许页面保留同源权限(否则视为独立源,无法访问同源Cookie);- 其他可选值:
allow-scripts(允许脚本执行)、allow-forms(允许表单提交)等,默认全部禁止。
3. 升级不安全请求(upgrade-insecure-requests)
自动将页面中的HTTP请求升级为HTTPS,解决“混合内容”问题(HTTPS页面加载HTTP资源导致的安全警告或拦截)。
示例:
Content-Security-Policy: upgrade-insecure-requests;
- 效果:页面中
<img src="http://example.com/img.png">会自动变为https://example.com/img.png; - 配合
block-all-mixed-content(禁止所有混合内容)使用,进一步增强安全性。
4. 报告机制(report-uri/report-to)
CSP支持将“违反策略的行为”(如加载未授权脚本、执行内联代码)发送到指定服务器端点,用于监控和调试。
-
report-uri(传统方式):Content-Security-Policy: default-src 'self'; report-uri /csp-reports;浏览器会向
/csp-reports发送JSON格式的报告,包含违规资源URL、触发指令、页面URL等信息。 -
report-to(现代方式,配合Reporting API):Content-Security-Policy: default-src 'self'; report-to csp-endpoint; Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"/csp-reports"}]}更强大的报告机制,支持批量发送、过期时间设置等。
5. 强制HTTPS(block-all-mixed-content)
禁止HTTPS页面加载任何HTTP资源(混合内容),防止中间人攻击篡改HTTP资源注入恶意代码。
示例:
Content-Security-Policy: block-all-mixed-content;
三、CSP的工作模式
CSP支持两种工作模式,用于不同阶段的部署和调试:
-
强制模式(Enforcement):
浏览器严格执行CSP策略,拒绝未授权资源,并可能阻止页面加载(如script-src违规时可能阻止所有脚本)。
配置方式:Content-Security-Policy: ... -
仅报告模式(Report-Only):
浏览器不执行策略(允许未授权资源加载),但会将违规行为发送到report-uri,用于上线前测试策略是否合理(避免误拦截正常资源)。
配置方式:Content-Security-Policy-Report-Only: ...
四、优势与局限性
优势:
- 主动防御XSS:通过白名单限制脚本来源,从根本上阻止未授权脚本执行(即使攻击者注入恶意代码,也会被拦截);
- 细粒度控制:可精确到“哪种资源允许从哪个域名加载”,满足复杂业务场景;
- 可监控性:通过报告机制实时发现潜在攻击或策略配置问题;
- 兼容性好:所有现代浏览器(Chrome、Firefox、Edge、Safari)均支持核心指令。
局限性:
- 配置复杂:需梳理所有资源来源(如CDN、第三方服务),初期配置成本高;
- 内联代码兼容问题:默认禁止内联脚本/样式,需通过nonce/哈希改造,对老旧系统不友好;
- 过度宽松风险:若配置
script-src *或'unsafe-inline',则CSP几乎失效; - 无法防御所有攻击:对服务器端注入(如SQL注入)、纯数据泄露(如敏感信息直接输出)无防护作用。
五、最佳实践
- 从严格到宽松:初期使用
default-src 'none',逐步开放必要的资源来源(最小权限原则); - 避免危险值:尽量不用
'unsafe-inline'、'unsafe-eval'、*,必须使用时配合nonce/哈希降低风险; - 先测试后上线:先用
Report-Only模式运行1-2周,收集违规报告并调整策略,再切换到强制模式; - 结合其他措施:CSP不是银弹,需配合输入验证(过滤恶意输入)、输出编码(转义特殊字符)、
HttpOnlyCookie等机制,形成多层防护; - 监控报告:定期分析CSP报告,发现异常访问(如频繁尝试加载恶意域名),及时优化策略。
总结
CSP是现代Web安全的核心机制,通过“白名单控制资源加载”从根本上防御XSS等代码执行攻击。其核心价值在于将安全策略从“被动检测恶意内容”转变为“主动允许可信内容”,大幅降低攻击面。尽管配置复杂,但对于用户数据敏感、安全要求高的应用(如金融、电商、社交),CSP是不可或缺的安全防线。
浙公网安备 33010602011771号