双击劫持怎么防?用户点按钮却触发了隐藏操作?

程序猿淑芳 阅读 3

我在做支付页面时,发现攻击者可能用透明iframe覆盖我的按钮,诱导用户“双击”——第一次点击激活iframe,第二次实际触发了恶意操作。我试过加X-Frame-Options: DENY,但有些老系统必须允许嵌入,这咋办?

有没有前端能用的方案?比如检测是否被嵌套或者阻止非主动点击?

if (window.top !== window.self) {
  // 被嵌套了,但光跳转可能不够,用户已经点了...
}
我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
开发者雅涵
既然业务上必须允许嵌入,那就不能简单粗暴地禁止 iframe,这时候核心思路就是做严格的来源白名单,只放行你信任的那个老系统域名,其他的一律拦截。单纯靠 JS 检测嵌套是不够的,因为攻击者可以在 iframe 上加 sandbox 属性或者重写顶层对象来绕过你的检测代码。

最稳妥的方案是结合 HTTP 头和前端交互确认。

先说服务端,弃用 X-Frame-Options,改用 CSP (Content Security Policy) 的 frame-ancestors 指令,这样控制力更细。在响应头里加上:

Content-Security-Policy: frame-ancestors 'self' https://your-trusted-legacy-system.com;


这样只有你指定的老系统能嵌套,攻击者的恶意网站因为域名不在白名单里,浏览器直接拒绝加载,根本没机会搞透明覆盖。

前端这块,既然你担心用户已经点了,那就得在关键操作上加一道“确认门槛”。支付按钮这种高危操作,不要一点就发请求,最好弹个模态框让用户再次确认,或者输入支付密码。攻击者虽然能覆盖按钮骗到第一次点击,但他很难模拟用户在模态框里的确认操作,这能打断攻击链。

如果你非要写 JS 防御,可以改进一下你的检测代码,防止被沙箱隔离:

// 防止被嵌套在恶意域名的 iframe 中
if (window.top !== window.self) {
try {
// 尝试访问父级域名,看是不是在白名单里
var parentDomain = window.top.document.domain;
var allowedDomains = ['your-trusted-legacy-system.com', 'localhost'];

var isAllowed = allowedDomains.some(function(domain) {
return parentDomain.indexOf(domain) !== -1;
});

if (!isAllowed) {
// 不在白名单,强制跳转回自己的首页
window.top.location = self.location;
}
} catch (e) {
// 如果报错(通常是跨域了),说明父级不可信,直接跳转
window.top.location = self.location;
}
}


最后提醒一下,任何前端防御(JS 检测、点击确认)在懂行的攻击者面前都有被绕过的风险,比如攻击者诱导用户关闭某些保护或者配合其他浏览器漏洞。所以一定要把 CSP 白名单加上,这才是后盾。支付接口那边也要做二次校验,比如校验 Referer 或者 Token,不要只看前端传来的参数。
点赞
2026-03-04 15:11