内容安全策略(CSP)详解
字数 2096 2025-11-12 03:30:54
内容安全策略(CSP)详解
1. 什么是内容安全策略(CSP)?
内容安全策略是一种通过HTTP响应头(Content-Security-Policy)或HTML元标签(<meta>)定义的网络安全机制,用于限制网页中可以加载或执行的资源(如脚本、样式、图片等),从而减少跨站脚本攻击(XSS)和数据注入攻击的风险。
核心思想:通过白名单机制,明确告诉浏览器哪些来源的资源是可信的,禁止加载或执行非白名单内的资源。
2. 为什么需要CSP?
以XSS攻击为例:攻击者通过注入恶意脚本(如<script>alert('XSS')</script>)到网页中,浏览器无法区分脚本是否合法,会直接执行。CSP通过以下方式防御:
- 禁止内联脚本(如
<script>标签或事件处理函数onclick),除非显式允许。 - 限制外部资源(如JS文件、CSS、图片)只能从特定域名加载。
3. CSP的配置语法
CSP策略由多个指令组成,每个指令对应一类资源。常见指令包括:
default-src:默认策略(适用于未单独指定的资源类型)。script-src:控制JavaScript的加载与执行。style-src:控制CSS样式表。img-src:控制图片资源。connect-src:控制Ajax请求、WebSocket等连接。font-src:控制字体文件。frame-src:控制嵌入的框架(如<iframe>)。
示例策略:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; img-src *;
default-src 'self':默认只允许同源资源。script-src 'self' https://trusted.cdn.com:脚本仅允许同源或trusted.cdn.com。img-src *:图片允许从任何域名加载。
4. CSP指令的取值规则
每个指令的值由来源表达式组成,常见取值包括:
'self':仅允许同源资源。'none':禁止所有资源。'unsafe-inline':允许内联脚本或样式(降低安全性)。'unsafe-eval':允许动态代码执行(如eval())。https::允许所有HTTPS域名。- 具体域名(如
https://example.com)。 - 哈希值(如
'sha256-abc123...'):匹配特定内联脚本的哈希。 - 随机数(
nonce,如'nonce-xyz'):匹配带有nonce属性的脚本。
5. 逐步配置CSP的策略
步骤1:分析现有资源依赖
检查页面需要加载的所有资源(JS、CSS、图片等),记录其来源。例如:
- 脚本:同源脚本、jQuery(CDN)、Google Analytics。
- 图片:同源图片、第三方图片服务(如
https://img.example.com)。
步骤2:制定初步策略
假设页面结构如下:
<script src="/js/local.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/jquery.min.js"></script>
<img src="https://img.example.com/logo.png">
初步CSP策略:
Content-Security-Policy:
script-src 'self' https://cdn.jsdelivr.net;
img-src 'self' https://img.example.com;
default-src 'self';
步骤3:处理内联脚本和样式
如果页面存在内联脚本(如<script>alert('test')</script>),CSP默认会阻止。解决方案:
- 避免内联代码:将脚本移到外部文件。
- 使用nonce(推荐):
- 生成随机数(如
nonce="rAnDoM123")添加到脚本标签:<script nonce="rAnDoM123">alert('Allowed')</script> - CSP头中包含相同的nonce:
Content-Security-Policy: script-src 'nonce-rAnDoM123';
- 生成随机数(如
- 使用哈希:
- 计算内联脚本的SHA256哈希值:
echo -n "alert('Allowed')" | openssl dgst -sha256 -binary | openssl base64 - 将哈希值加入策略:
Content-Security-Policy: script-src 'sha256-abc123...';
- 计算内联脚本的SHA256哈希值:
步骤4:处理动态代码执行
如果页面使用eval()或new Function(),需添加'unsafe-eval'(但应尽量避免):
Content-Security-Policy: script-src 'self' 'unsafe-eval';
6. 报告模式与调试
部署CSP前,可先启用报告模式,让浏览器报告违规行为但不阻止:
- 使用
Content-Security-Policy-Report-Only头:Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint; - 浏览器会将违规信息以JSON格式POST到
report-uri指定的端点,用于分析需调整的策略。
7. 进阶优化
- 严格动态(Strict Dynamic):
通过'strict-dynamic'允许由可信脚本动态加载的依赖,适用于现代模块化应用。 - 帧祖先限制:
使用frame-ancestors 'self'防止点击劫持,替代旧的X-Frame-Options头。 - 升级请求:
通过upgrade-insecure-requests自动将HTTP资源转换为HTTPS。
8. 常见问题与绕过案例
- JSONP绕过:如果白名单包含允许JSONP的域名,攻击者可能通过JSONP回调执行恶意代码。
- 重定向绕过:若白名单域名存在开放重定向漏洞,可能被利用加载恶意资源。
- 策略注入:若CSP头部分内容由用户输入控制,可能导致策略被篡改(如添加
unsafe-inline)。
总结
CSP是防御XSS和数据注入的关键工具,但需根据实际资源依赖精细配置。最佳实践包括:
- 最小化白名单范围。
- 优先使用
nonce或哈希替代unsafe-inline。 - 通过报告模式逐步调试。
- 定期审计策略,避免遗留漏洞。