阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 防御点击劫持的方法(如 X-Frame-Options)

防御点击劫持的方法(如 X-Frame-Options)

作者:陈川 阅读数:54725人阅读 分类: 前端安全

点击劫持是一种恶意攻击手段,攻击者通过透明或伪装的iframe覆盖在合法页面上,诱导用户点击看似无害的元素,实际触发隐藏的恶意操作。防御点击劫持的核心方法包括设置HTTP头、JavaScript防护以及现代浏览器提供的安全策略。

X-Frame-Options 的工作原理

X-Frame-Options 是一个HTTP响应头,用于控制页面是否允许被嵌入到 <frame><iframe><object> 中。它有三个可选值:

  1. DENY:完全禁止页面被嵌入到任何框架中。
  2. SAMEORIGIN:仅允许同源页面嵌入。
  3. ALLOW-FROM uri:允许指定来源的页面嵌入(已废弃,部分浏览器支持)。
# Nginx 配置示例
add_header X-Frame-Options "SAMEORIGIN";
# Apache 配置示例
Header always set X-Frame-Options "DENY"

Content-Security-Policy 的 frame-ancestors 指令

现代浏览器推荐使用 Content-Security-Policy (CSP) 的 frame-ancestors 指令替代 X-Frame-Options,因为它提供了更细粒度的控制:

Content-Security-Policy: frame-ancestors 'self' https://trusted.example.com;

此配置仅允许当前域名和 trusted.example.com 嵌入页面。若需完全禁止嵌套,可设置为:

Content-Security-Policy: frame-ancestors 'none';

JavaScript 防御方案

对于不支持HTTP头的旧环境,可通过JavaScript检测页面是否被嵌套:

if (window !== window.top || window.top.location !== window.location) {
  window.top.location = window.location;
}

更完善的方案需结合 try-catch 避免沙箱限制:

try {
  if (window.self !== window.top) {
    document.body.style.visibility = 'hidden';
    window.top.location = window.location;
  }
} catch (e) {
  console.error('Frame busting blocked:', e);
  document.body.innerHTML = '此页面不允许被嵌入框架';
}

多层级嵌套与沙箱限制

当页面被嵌套在多层iframe中,或沙箱属性限制了JavaScript执行时,需额外处理:

  1. 沙箱iframe检测

    if (window.self !== window.top) {
      try {
        parent.document; // 尝试访问父文档,沙箱中会抛出异常
      } catch (e) {
        document.body.innerHTML = '<h1>请直接访问此页面</h1>';
      }
    }
    
  2. CSS 视觉干扰防护

    body { display: none !important; }
    @media all {
      html { background: url("data:image/png;base64,...") repeat; }
    }
    

    通过CSS强制隐藏内容,除非页面是顶级窗口。

实际场景中的组合策略

  1. 关键操作二次确认

    function confirmAction() {
      if (window.self === window.top) {
        performPayment();
      } else {
        showModal('请在独立窗口中完成此操作');
      }
    }
    
  2. 登录态敏感操作: 结合后端验证 RefererOrigin 头:

    # Django 中间件示例
    class ClickjackingMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            response = self.get_response(request)
            if request.path.startswith('/payment/'):
                response['X-Frame-Options'] = 'DENY'
                response['Content-Security-Policy'] = "frame-ancestors 'none'"
            return response
    

浏览器兼容性与降级方案

  1. 特性检测

    const supportsCSP = 'Content-Security-Policy' in document.createElement('meta');
    if (!supportsCSP) {
      document.write('<meta http-equiv="X-Frame-Options" content="DENY">');
    }
    
  2. 服务端动态适配

    app.use((req, res, next) => {
      const userAgent = req.headers['user-agent'];
      const isOldBrowser = /MSIE [6-8]|Firefox\/[1-3]/.test(userAgent);
      res.setHeader(isOldBrowser ? 'X-Frame-Options' : 'Content-Security-Policy', 
                    isOldBrowser ? 'DENY' : "frame-ancestors 'none'");
      next();
    });
    

框架集成示例

  1. React 防护方案: 在根组件中添加防护逻辑:

    useEffect(() => {
      const handleFrameCheck = () => {
        if (window.self !== window.top) {
          window.location.href = `${window.location.origin}/frame-warning`;
        }
      };
      handleFrameCheck();
      window.addEventListener('focus', handleFrameCheck);
      return () => window.removeEventListener('focus', handleFrameCheck);
    }, []);
    
  2. Vue 指令实现

    Vue.directive('anti-framing', {
      inserted(el) {
        if (window.self !== window.top) {
          el.style.display = 'none';
          document.body.innerHTML = '<div class="fullscreen-warning">安全提示:请勿在框架内打开此页面</div>';
        }
      }
    });
    

移动端特殊处理

移动端浏览器可能对iframe的处理存在差异,需额外注意:

  1. WebView 防护

    // Android WebView 配置
    webView.getSettings().setAllowUniversalAccessFromFileURLs(false);
    webView.getSettings().setAllowFileAccessFromFileURLs(false);
    
  2. iOS 弹窗拦截

    document.addEventListener('click', (e) => {
      if (window.self !== window.top && e.target.closest('.sensitive')) {
        e.preventDefault();
        window.open(window.location.href, '_blank');
      }
    }, { capture: true });
    

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌