JS检测浏览器开发者工具是否打开的方法详解

作者:交互手记

时间:2026-10-23

浏览:380

本文详细解析了前端JavaScript检测浏览器开发者工具是否打开的三种主要方法:重写toString()、debugger断点机制以及窗口大小检测。文章分析了各方案的实现原理、代码示例及局限性,如toString仅能捕获状态切换,debugger可能被Deactive breakpoint绕过,窗口大小检测无法识别独立窗口模式。

文章目录

JS检测浏览器开发者工具是否打开的方法详解

在某些业务场景下,我们需要判断用户是否开启了浏览器的开发者工具。例如在前端反爬虫策略中,若检测到控制台已开启,则将其视为潜在爬虫用户并采取相应限制措施。本文将深入探讨几种通过前端JavaScript检测开发者工具开启状态的技术方案。

 JS检测浏览器开发者工具是否打开的方法详解 

一、重写toString()方法

一、重写toString()方法

针对Chrome、Firefox等浏览器,当控制台输出对象时,会保留该对象的引用。每次打开开发者工具查看该对象时,浏览器会重新调用该对象的toString()方法,并将返回结果打印在控制台(Console Tab)中。

基于此特性,我们可以创建一个对象并重写其toString()方法。在页面初始化时将该对象打印至控制台(此时假设控制台未开启)。当用户后续打开开发者工具查看该对象时,会触发toString()方法的调用,从而捕获到用户打开控制台的行为。

以下示例展示了当Chrome用户的开发者工具状态由关闭转为打开时,该动作会被捕获并执行回调函数:


<html>
<head>
  <title>console detect test</title>
</head>
<body>
<script>
 
  /**
   * 控制台打开的时候回调方法
   */
  function consoleOpenCallback(){
    alert("CONSOLE OPEN");
    return "";
  }
 
  /**
   * 立即运行函数,用来检测控制台是否打开
   */
  !function () {
    // 创建一个对象
    let foo = /./;
    // 将其打印到控制台上,实际上是一个指针
    console.log(foo);
    // 要在第一次打印完之后再重写toString方法
    foo.toString = consoleOpenCallback;
  }()
 
</script>
</body>
</html>

效果演示如下:

 JS检测浏览器开发者工具是否打开的方法详解

需要注意的是,此方法仅在首次打开控制台时触发。若用户在已开启控制台的窗口中粘贴网址访问,或在该页面已开启控制台的情况下刷新页面,则不会触发检测。

尽管该方法较为巧妙,但缺乏通用性,且仅能捕获开发者工具从关闭到打开的状态转移过程,存在一定局限性。

二、利用debugger语句

二、利用debugger语句

类似于代码调试中的断点,当浏览器开启开发者工具(即Debug模式)并遇到debugger语句时,程序执行会暂停:

JS检测浏览器开发者工具是否打开的方法详解

此时用户需点击蓝色的“Resume script execution”按钮以继续执行,这一过程会产生时间差。通过判断该时间差是否超过设定阈值,即可推断开发者工具是否开启。该方法不会造成误判,未开启工具时debugger语句不会暂停,因此通用性较好。

以下是使用debugger语句检测开发者工具开启状态的示例:


<html>
<head></head>
<body>
<script>
 
  function consoleOpenCallback() {
    alert("CONSOLE OPEN");
  }
 
  !function () {
    const handler = setInterval(() => {
      const before = new Date();
      debugger;
      const after = new Date();
      const cost = after.getTime() - before.getTime();
      if (cost > 100) {
        consoleOpenCallback();
        clearInterval(handler)
      }
    }, 1000)
  }();
 
</script>
</body>
</html>

效果演示如下:

 JS检测浏览器开发者工具是否打开的方法详解

然而,上述代码存在一个严重缺陷:若用户在执行到debugger语句时察觉异常,未点击“Resume script execution”而是直接退出页面,则无法检测到本次开启行为,导致实际结果与预期不符。这类似于电影中踩中地雷后及时察觉并缩脚以保命,若用户识别出这是检测代码并退出,使用其他手段绕过,则检测功能将失效。

使用此方法时需注意,当程序卡在debugger语句处,用户可见附近的代码。若用户具备一定经验,可轻易识破其中逻辑。因此,需隐藏真实目的,例如隐藏debugger语句并对代码进行混淆以增加阅读难度。关于如何隐藏debugger语句前后的逻辑,可参考以下网站(截至2018-7-4 23:12:17有效):

http://app2.sfda.gov.cn/datasearchp/gzcxSearch.do?formRender=cx&optionType=V1

https://www.qimai.cn/

使用此方案时需注意,debugger语句可能不会暂停。例如在Chrome浏览器的Source面板中,若选择“Deactive breakpoint”,则debugger语句不会暂停。

JS检测浏览器开发者工具是否打开的方法详解

若该按钮被激活,测试上述网页会发现检测代码失效,因为debugger语句并未暂停执行。

此外,debugger语句还可用于反调试。例如设置每秒触发一次debugger,使调试者疲于应付或增加其覆盖JS的成本。上述几个网站即采用此策略。

以下是使用debugger语句进行JS反调试的简单示例:


<html>
<head>
  <title>Anti debug</title>
</head>
<body>
<script>
 
  !function () {
    setInterval(() => {
      debugger;
    }, 1000);
  }();
 
</script>
</body>
</html>

效果演示如下:

JS检测浏览器开发者工具是否打开的方法详解

一个实际案例是网站:http://jxw.uou0.com/的JS检测脚本,其针对不同情况采取不同的反调试策略。

注意,复现此场景需粘贴视频地址解析后才会加载检测脚本。例如可尝试解析该视频:http://film.qq.com/film/p/topic/thwjlxby/index.html。

当未打开开发者工具进行解析,随后打开开发者工具时,将使用此检测方式:


!function() {
  var timelimit = 50;
  var open = false;
  setInterval(function() {
    var starttime = new Date();
    debugger ;if (new Date() - starttime > timelimit) {
      open = true;
      window.stop();
      $("#loading").hide();
      $("#a1").remove();
      $("#error").show();
      $("#error").html("\u7cfb\u7edf\u68c0\u6d4b\u975e\u6cd5\u8c03\u8bd5\u002c\u8bf7\u5237\u65b0\u91cd\u8bd5\u0021")
    } else {
      open = false
    }
  }, 500)
}();

由于该网站提供VIP视频免费解析,一旦检测到有人打开开发者工具进行调试,便会移除解析好的视频,并弹出提示框:

JS检测浏览器开发者工具是否打开的方法详解

若已打开开发者工具再粘贴地址进行视频解析,则会触发无限debugger。

应对上述脚本最简单的方法是将Chrome浏览器设定为“Deactive breakpoint”,此时上述脚本将失效,但同时也影响自身调试。用于反调试确实能增加对方成本,较好的方法是使用Fiddler修改网页返回内容,过滤掉debugger语句以破解此套路。

三、检测窗口大小

三、检测窗口大小

检测窗口大小相对简单,需明确两个概念:窗口的outer大小和inner大小:

window.innerWidth / window.innerHeight:表示可视区域的宽高,其中window.innerWidth包含纵向滚动条的宽度,window.innerHeight包含水平(横向)滚动条的宽度。

window.outerWidth / window.outerHeight:在innerWidth和innerHeight的基础上加上工具栏的宽度。

关于窗口大小检测,此处不自行编写示例,已有专门针对此功能的库:https://github.com/sindresorhus/devtools-detect。该库拥有数百个Star,质量较高。代码较为简单,GitHub上有使用说明。此处仅对其核心代码进行分析,并附上本人对该库核心代码的分析:


/* eslint-disable spaced-comment */
/*!
  devtools-detect
  Detect if DevTools is open
  https://github.com/sindresorhus/devtools-detect
  by Sindre Sorhus
  MIT License
  comment by CC11001100
*/
(function () {
  'use strict';
  var devtools = {
    open: false,
    orientation: null
  };
  // inner大小和outer大小超过threshold被认为是打开了开发者工具
  var threshold = 160;
  // 当检测到开发者工具后发出一个事件,外部监听此事件即可,设计得真好,很好的实现了解耦
  var emitEvent = function (state, orientation) {
    window.dispatchEvent(new CustomEvent('devtoolschange', {
      detail: {
        open: state,
        orientation: orientation
      }
    }));
  };
 
  // 每500毫秒检测一次开发者工具的状态,当状态改变时触发事件
  setInterval(function () {
    var widthThreshold = window.outerWidth - window.innerWidth > threshold;
    var heightThreshold = window.outerHeight - window.innerHeight > threshold;
    var orientation = widthThreshold ? 'vertical' : 'horizontal';
 
    // 第一个条件判断没看明白,heightThreshold和widthThreshold不太可能同时为true,不论是其中任意一个false还是两个都false取反之后都会为true,此表达式恒为true
    if (!(heightThreshold && widthThreshold) &&
      // 针对Firebug插件做检查
      ((window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) || widthThreshold || heightThreshold)) {
      // 开发者工具打开,如果之前开发者工具没有打开,或者已经打开但是靠边的方向变了才会发送事件
      if (!devtools.open || devtools.orientation !== orientation) {
        emitEvent(true, orientation);
      }
 
      devtools.open = true;
      devtools.orientation = orientation;
    } else {
      // 开发者工具没有打开,如果之前处于打开状态则触发事件报告状态
      if (devtools.open) {
        emitEvent(false, null);
      }
 
      // 将标志位恢复到未打开
      devtools.open = false;
      devtools.orientation = null;
    }
  }, 500);
 
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = devtools;
  } else {
    window.devtools = devtools;
  }
 
})();

缺点分析:

1. 使用window属性检查大小可能存在浏览器兼容性问题,因非专业前端仅测试了Chrome和Firefox,结果无误。

2. 此方案仍有漏洞。以Chrome浏览器为例,开发者工具窗口有四种选项:单独窗口、靠左、靠下、靠右。

JS检测浏览器开发者工具是否打开的方法详解

靠左、靠右、靠下会占用当前窗口部分空间,此种情况可被检测到;但独立窗口不占用打开网页窗口的空间,因此无法检测。可前往此页面验证:https://sindresorhus.com/devtools-detect/。

四、总结

四、总结

本文介绍了几种检测方式,各有利弊。以下是对各方案缺点的简要总结:

重写toString():仅能捕获开发者工具从关闭状态向打开状态转移的过程。

debugger语句:当勾选Chrome浏览器的“Deactive breakpointJS检测浏览器开发者工具是否打开的方法详解”时,debugger语句不会暂停,导致无法捕获。

检测窗口大小:当开发者工具以独立窗口模式打开时,无法检测到。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章