最直接确认页面是否被 iframe 嵌套的方法是早期执行 window.top !== window.self 判断并立即跳转,而非依赖 referrer 或 DOMContentLoaded 后检测。
最直接的办法是运行一段检测脚本,而不是等攻击发生后再补救。关键不是“有没有 iframe”,而是“当前页面是否处于 window.top !== window.self 状态”。这个判断必须在 DOM 加载早期执行,否则可能被后续脚本覆盖或绕过。
常见错误现象:把检测逻辑放在 DOMContentLoaded 之后,或包裹在第三方库初始化回调里——此时攻击者早已完成透明层覆盖;更糟的是只检查 parent !== window,漏掉嵌套在多层 iframe 中的场景。
window.top !== window.self,它能穿透任意深度嵌套window.top.location = window.location)比仅提示用户更可靠document.referrer 判断来源,它可被伪造frame-ancestors 是现代浏览器唯一推荐的防御方式,但写错就等于没写。它不继承、不 fallback,且值为空格分隔的源列表,不是正则也不是通配符。
典型错误:写成 frame-ancestors 'self' https://trusted.example.com 却忘了末尾分号;或误用 * 允许任意嵌入;或在 Express 中用 res.set('Content-Security-Policy', ...) 覆盖了其他必要指令(如 script-src)。
立即学习“前端免费学习笔记(深入)”;
Content-Security-Policy: frame-ancestors 'self';
'self' 指当前协议+主机+端口,不包含子域名;要允许子域名得显式列出:frame-ancestors 'self' https://admin.example.com;
frame-ancestors *,Chrome/Firefox 已无视该写法X-Frame-Options,现代浏览器会优先采用 CSP,但旧版 IE 只认前者,建议双写(DENY 优先级高于 SAMEORIGIN)禁用 oncontextmenu 或 user-select: none 对点击劫持完全无效——攻击者根本不需要用户右键或复制,只要诱使鼠标左键落在透明 iframe 的目标按钮上就行。这类措施只干扰普通用户,反而给开发者一种“已防护”的错觉。
真实风险在于:你加了 onselectstart="return false",却没设 CSP;你用了 iframe 沙箱属性,却忘了 sandbox 默认禁用脚本,导致自己页面的 JS 失效;你混淆了 JS,但敏感操作仍暴露在 HTML 层。
sandbox="allow-scripts" 或禁用 JS 绕过本地测试时,很多人打开 test.html 就看“页面有没有显示”,这完全跑偏。重点不是渲染结果,而是目标页面是否静默加载成功并保持登录态。
最容易被忽略的三个条件:测试前未登录目标站、目标页返回了 302 跳转到登录页、服务端设置了 Set-Cookie 但没带 SameSite=Lax 导致跨域请求丢失凭证。
withdraw 类接口发出且状态码为 200(不是 302 或 401)iframe,确认子帧 DOM 已挂载,且其 src 属性值与你填写的一致document.domain = 'example.com',而测试页域名不同,iframe 会因同源策略失败——这不是防护生效,是跨域报错真正难的不是加一行 header,而是厘清哪些页面必须绝对禁止嵌入(如支付页)、哪些可以有条件允许(如帮助文档)、哪些要支持嵌入但需鉴权(如报表看板)。这些决策一旦写死在 CSP 里,改起来牵一发而动全身。