JS 检测开发者工具

JS检测浏览器开发者工具是否打开

在某些情况下我们需要检测当前用户是否打开了浏览器开发者工具,比如前端爬虫检测,如果检测到用户打开了控制台就认为是潜在的爬虫用户,再通过其它策略对其进行处理。本篇文章主要讲述几种前端JS检测开发者工具是否打开的方法。

重写toString()

简单来说就是捕获控制台打开的情况

  • 缺点是不具有通用性,并且只能捕获到开发者工具处于关闭状态向打开状态转移的过程,具有一定的局限性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<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>

WX20190906-180237@2x

debugger

类似于代码里的断点,浏览器在打开开发者工具时(对应于代码调试时的debug模式)检测到debugger标签(相当于是程序中的断点)的时候会暂停程序的执行, qimai 就是这种方式

784924-20180704231334677-1292537348

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<head>
<title>Anti debug</title>
</head>
<body>
<script>

!function () {
setInterval(() => {
debugger;
}, 1000);
}();

</script>
</body>
</html>

检测窗口大小

检测窗口大小比较简单,首先要明确两个概念,窗口的outer大小和inner大小:

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

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

关于检测窗口大小,不再自己写例子,有人专门针对此写了个库:https://github.com/sindresorhus/devtools-detect,毕竟几百个star,比我这个渣渣写的好多了,代码比较简单,使用部分其github都有说明,这里只对其核心代码做个分析,此处贴出鄙人对此库核心代码的分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/* 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和ff是没有问题的。

  2. 此方案还是有漏洞的,就拿Chrome浏览器来说,开发者工具窗口有四个选项:单独窗口、靠左、靠下、靠右。

靠左、靠右、靠下都会占用当前窗口的一些空间,这种情况会被检测到,但是独立窗口并不会占用打开网页窗口的空间,所以这种情况是检测不到的,可去此页面进行验证:https://sindresorhus.com/devtools-detect/。

解决 debugger

一 强行设置判断点

755429799-5c88738e19536_articlex

二 中间拦截

我是 mac 电脑,不能用 FD 抓包工具,目前是用的 Charles

屏幕快照 2019-09-19 下午3.06.11
利用断点模式,拦截修改 Response

或 如果条件允许的情况下,可以下载要修改的 response,本地修改好后替换
右键需要操作的请求,选择 Map Location 即可。

三 设值

通常情况下是通过一个判断来启动 debugger, 那么我们就在窗口设置js中判断的值,与第一种方法,有异曲同工之处