如何防止页面中的按钮被Strokejacking攻击?

Zz爱景 阅读 44

我在开发一个在线支付页面时,发现按钮区域容易被恶意页面通过透明IFrame覆盖,导致用户误触转账操作。虽然设置了X-Frame-Options: DENY,但测试时发现攻击页面仍然能嵌套我的页面。

我尝试给按钮添加了style="pointer-events: none",但这样会导致正常用户也无法点击按钮。查看攻击页面代码发现他们用了allowtransparency属性,这和我之前了解的防御方法好像不太一样…

现在卡在如何同时满足:1. 允许合法框架嵌套(有些合作方需要) 2. 确保关键按钮区域无法被覆盖点击。有什么更可靠的防御方案吗?

我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
闲人智慧
你这个问题的核心不是 X-Frame-Options,而是防点击劫持(Clickjacking)的底层逻辑没搞对。X-Frame-Options DENY 是防嵌套的,但攻击者如果是在自己的页面里嵌你的页面(比如通过 iframe),然后在 iframe 上叠个透明层,确实能绕过一些基础防护。

关键点来了:不能只靠服务端头,得前端主动防。
直接用 X-Frame-Options: SAMEORIGIN 配合 Content-Security-Policy: frame-ancestors 'self'(CSP 更现代,优先用这个),但你说了要允许合作方嵌,那 frame-ancestors 就得加白名单域名。

不过最靠谱的方案是:前端拦截非预期来源的 iframe 嵌套 + 关键区域加防层。

先说服务端配置(Nginx 举例):
add_header Content-Security-Policy "frame-ancestors 'self' https://trusted-partner.com https://another.co;";
add_header X-Frame-Options "DENY";

注意:frame-ancestors 生效时,X-Frame-Options 会被忽略,所以只配 CSP 就行,但为了兼容老浏览器可以俩都加。

然后前端加一层防穿透逻辑,直接用 JS 检测是否被嵌套,如果不是预期来源就干掉 iframe 或遮罩关键按钮:

(function() {
try {
if (window.top !== window.self) {
// 被嵌套了,检查来源
const allowedOrigins = ['https://yourdomain.com', 'https://trusted-partner.com'];
const origin = document.referrer ? new URL(document.referrer).origin : '';
if (!allowedOrigins.includes(origin)) {
// 不在白名单里,直接断开 iframe 或加遮罩
const buttons = document.querySelectorAll('button[type="submit"], .pay-btn');
buttons.forEach(btn => {
btn.style.pointerEvents = 'none';
btn.style.filter = 'blur(2px)';
});
// 或者更狠点:整页遮罩
const overlay = document.createElement('div');
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100vw';
overlay.style.height = '100vh';
overlay.style.zIndex = '999999';
overlay.style.background = 'rgba(255,255,255,0.95)';
overlay.innerHTML = '<div style="text-align:center;margin-top:200px;">此页面不允许在其他网站中嵌入,请直接访问官网。</div>';
document.body.appendChild(overlay);
return;
}
}
} catch (e) {
// 跨域访问 top 报错,说明被嵌套且跨域,直接防护
const overlay = document.createElement('div');
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100vw';
overlay.style.height = '100vh';
overlay.style.zIndex = '999999';
overlay.style.background = 'white';
overlay.innerHTML = '<div style="text-align:center;margin-top:200px;">安全限制:禁止跨域嵌入</div>';
document.body.appendChild(overlay);
}
})();


另外,关键按钮区域加一层透明防层也行,但别用 pointer-events: none,而是用 pointer-events: none 只对非预期区域生效。比如:

<div class="btn-container" style="position:relative;">
<button class="pay-btn" style="position:relative; z-index:2;">支付</button>
<div class="click-guard" style="position:absolute; inset:0; z-index:1; pointer-events:none;"></div>
</div>


然后 JS 里动态控制 .click-guard 的 pointer-events:如果检测到被嵌套,就设成 auto 并拦截点击。

最后提醒:别信 allowtransparency 这种老属性,它是让 iframe 背景透明用的,和攻击无关,别被带偏了。
真要防点击劫持,记住:服务端 CSP 白名单 + 前端运行时检测 + 关键按钮动态防护,三者结合才稳。
点赞 3
2026-02-25 21:16
宇文雯婧
frame-ancestors 指令代替 X-Frame-Options,CSP 的 frame-ancestors 更灵活,能指定允许嵌套的域名。关键按钮区域加个透明的 div 盖在上面,攻击者点不到按钮也搞不了事情。

<style>
#protective-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
background: transparent;
}
</style>

<div id="protective-layer"></div>
<button id="critical-button">支付</button>


差不多就行,记得把 #protective-layer 调整到合适的范围,别挡了正常功能。
点赞 10
2026-02-15 13:17