Web 安全

点击劫持

约 3 分钟阅读

什么是点击劫持

点击劫持 (Clickjacking) 是一种使用透明或不可见的 iframe 将合法网页覆盖在用户屏幕上,诱导用户进行非预期点击操作的攻击手法。将其他内容覆盖在可见 UI 之上、使用户产生错觉的攻击统称为 UI Redressing (UI 伪装),点击劫持是其中的代表。

攻击者创建一个陷阱页面,并在其上方用透明的 iframe 覆盖目标站点。用户看到的是陷阱页面的按钮和链接,但实际点击的是透明 iframe 中目标站点的元素。这样,用户在不知情的情况下就会执行「点赞」、设置变更、转账确认等操作。

攻击原理与手法

点击劫持按以下步骤执行。

  1. 攻击者创建陷阱网页,放置有吸引力的内容 (视频播放按钮、游戏、抽奖表单等)
  2. 通过 iframe 加载目标站点,并用 CSS 设置 opacity: 0 (完全透明)
  3. 将透明 iframe 精确覆盖在陷阱页面的可点击元素上方
  4. 用户点击陷阱页面的按钮时,实际点击的是透明 iframe 中目标站点的按钮

进阶手法

  • 拖放利用:利用用户的拖动操作向透明 iframe 中的表单输入数据
  • 光标显示的伪装:通过 CSS 替换或隐藏光标图像,使看到的光标位置与实际的点击位置产生偏移,让用户点击非预期的位置
  • 多步攻击:诱导多次点击,甚至让用户点击确认对话框的「确定」按钮

XSSCSRF 结合时,可以构建更复杂的攻击场景。

防御措施的实现

点击劫持防御的核心是防止本站被其他站点的 iframe 嵌入。

CSP frame-ancestors 指令

CSPframe-ancestors 指令控制哪些父页面源可以将本站嵌入 iframe。它在 CSP Level 2 中作为 X-Frame-Options 的后继被引入,CSP 规范规定:两者同时指定时,应用 frame-ancestors 并忽略 X-Frame-Options。如果现在开始配置,应以它为基准。

  • frame-ancestors 'none':不允许任何站点通过 iframe 嵌入
  • frame-ancestors 'self':仅允许同源的嵌入
  • frame-ancestors https://trusted.example.com:仅允许特定源的嵌入

X-Frame-Options 头

2009 年至 2010 年间由各浏览器厂商作为非标准头引入,并于 2013 年被整理为 RFC 7034 (Informational) 的防御措施。实际使用的值有以下两个。

  • X-Frame-Options: DENY:拒绝所有 iframe 嵌入
  • X-Frame-Options: SAMEORIGIN:仅允许同源的嵌入

规范中还有第三个值 ALLOW-FROM <URI>,但它在主要浏览器中无法工作,因此不要使用。不支持它的浏览器会整个忽略这项设置,结果是没有留下任何防御。

另一个陷阱是 SAMEORIGIN 的比对范围。许多浏览器的实现只比对最顶层文档的源,因此把本站页面加载到本站的 iframe 中、再由攻击者页面在最顶层包裹整体的嵌套结构可以绕过它。frame-ancestors 会逐个比对祖先框架,所以没有这个漏洞。

同时设置两者时,支持 frame-ancestors 的浏览器会应用它,不支持的浏览器则由 X-Frame-Options 生效。重复指定不会互相抵消。

JavaScript 防御 (Frame Busting)

使用 if (top !== self) { top.location = self.location; } 这样的脚本,在被 iframe 加载时跳转到顶层框架。但由于攻击者可以通过 sandbox 属性限制 JavaScript 执行,因此只应作为 HTTP 头防御的补充。

实务防御检查清单

确保可靠实现点击劫持防御的检查清单。

  • 确认安全头配置:确认所有页面的响应中包含 X-Frame-Options: DENY (或 SAMEORIGIN) 和 CSP frame-ancestors
  • 识别需要 iframe 嵌入的页面:对于有合理理由允许 iframe 的页面 (如支付表单嵌入),严格限制允许的源
  • 保护关键操作:对于密码修改、转账、账户删除等关键操作,除 CSRF 令牌外还要求重新认证 (重新输入密码)
  • HSTS 配合:强制 HTTPS,防止通过中间人攻击移除安全头
  • 定期测试:定期测试本站是否可以被 iframe 嵌入。可使用浏览器开发者工具或安全扫描器验证

点击劫持单独来看可能危害不大,但与社会工程学结合后,是一种能在用户不知情的情况下执行关键操作的强大攻击手法。由于仅通过 HTTP 头配置就能防御,是性价比极高的安全措施。

常见误解

点击劫持是过时的攻击手法,现在已不构成威胁
成立条件只有「本站能被其他站点的 iframe 加载」这一点,在既未设置 X-Frame-Options 也未设置 CSP frame-ancestors 的页面上,截至 2026 年仍然成立。拥有一次点击就能确定结果的 UI (社交网络的分享按钮、OAuth 的授权页面、设置的开关等) 的站点,无论上线时间早晚,都需要确认自身的响应头。
仅靠 JavaScript 的 Frame Busting 就能充分防御
攻击者可以通过 iframe 的 sandbox 属性限制 JavaScript 执行,或通过 onbeforeunload 事件阻止框架跳转。基于 HTTP 头 (X-Frame-Options、CSP frame-ancestors) 的防御是必须的,JavaScript 只是辅助措施。
分享

相关术语

相关文章