为啥?

我经常喜欢打开开发者工具,看看网站的源码,dom之类的。看到喜欢的好看的页面,就会想办法看看是如何实现,甚至还会跑跑对方的接口。也会在一些收费或者VIP视频网站内看看是否可以钻一下漏洞,然后写一个油猴插件,增加使用体验。这就可能会对一些网站的拥有者造成了一些权益的损害。所以为了防止我们的代码被开发者调教,就得想办法在不影响正常用户的前提下增加调试者的门槛。

禁用右键+F12+(ctrl+shift+i)+(Shift+F10)

首先,第一道防线肯定是防止这位老哥打开devtool。

于是我们可以通过禁用右键与禁用F12的方法来防止唤起开发者工具。

// 禁止右键事件  
document.oncontextmenu = function noMenuOne() {
	 //alert('禁止右键菜单!'); 
	return false;
};
document.onkeydown = function () {
        if (window.event && window.event.keyCode == 123) {
            return false;
            //禁用ctrl+shift+i,
        } else if (window.event.ctrlKey && window.event.shiftKey && window.event.keyCode == 73) {
            return false;
            //屏蔽Shift+F10
        } else if (window.event.shiftKey && window.event.keyCode == 121) {
            return false;
        }
};//禁止F12

这确实可以防止很多小白打开开发者工具。

还可以先打开开发者工具再打开我们页面,所以,防不胜防啊家人们。

无限debugger

看到这个,很多前端老哥自己悟了。心想这还不简单。

(() => {
	function ban() {
	  setInterval(() => {
	    debugger;
	  }, 50);
	}
	try {
	  ban();
	} catch (err) { }
})();

反手一个自执行函数+无限调用等于无敌

但,真的这么简单吗?我们完全可以通过打开这个"停用断点"功能来绕过无限debugger。

或者通过忽略执行代码的方式,也可以避免无限debugger

不过忽略代码可以这样来绕过

debugger
// 替换为
Function("debugger")()

Function 构造器生成的 debugger 会在每一次执行时开启一个临时 js 文件。

于是这种对老开发来讲掩耳盗铃的操作,效果就不尽人意了。

所以我们还能做什么?

监听浏览器宽高变化

实时检测浏览器宽高与打开F12后的宽高进行比对,有差值,说明打开了开发者工具,则清空DOM。

(() => {
  function block() {
    if (window.outerHeight - window.innerHeight > 200 || window.outerWidth - window.innerWidth > 200) {
      document.body.innerHTML = "检测到非法调试";
    }
    setInterval(() => {
      (function () {
        return false;
      }
      ['constructor']('debugger')
      ['call']());
    }, 50);
  }
  try {
    block();
  } catch (err) { }
})();

这招确实逆天。但是仍然可以在"源代码/来源的位置查看封装后的源码等等"

但还有更强的方案

利用debugger特性禁止调试

我们运行下一段代码

  (() => {
    function block() {
      setInterval(function () {
        var startTime = performance.now();
        // 设置断点
        debugger;
        var endTime = performance.now();
        // 设置一个阈值,例如100毫秒
        if (endTime - startTime > 100) {
          window.location.href = 'about:blank';
        }
      }, 100);
    }
    try {
      block();
    } catch (err) { }
  })();

由于debugger是同步停顿,无论再快,经过测试,阈值也在100毫秒以上,我们可以通过这个方法来检查是否开启开发者工具。如果开了,就跳转空白页,这回确实啥都看不到了,我愿称为自己的版本答案。那,别人的版本答案是什么?

disable-devtool

这是一个开源的可以禁用所有一切可以进入开发者工具的库。

  • 支持可配置是否禁用右键菜单

  • 禁用 f12 和 ctrl+shift+i 等快捷键

  • 支持识别从浏览器菜单栏打开开发者工具并关闭当前页面

  • 开发者可以绕过禁用 (url参数使用tk配合md5加密)

  • 多种监测模式,支持几乎所有浏览器(IE,360,qq浏览器,FireFox,Chrome,Edge...)

  • 高度可配置、使用极简、体积小巧

  • 支持npm引用和script标签引用(属性配置)

  • 识别真移动端与浏览器开发者工具设置插件伪造的移动端,为移动端节省性能

  • 支持识别开发者工具关闭事件

  • 支持可配置是否禁用选择、复制、剪切、粘贴功能

  • 支持识别 eruda 和 vconsole 调试工具

  • 支持挂起和恢复探测器工作

  • 支持配置ignore属性,用以自定义控制是否启用探测器

  • 支持配置iframe中所有父页面的开发者工具禁用

功能之多,恐怖如斯。github 1.6K start。中文文档

使用

原生

<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@latest'></script>

npm

npm i disable-devtool
import DisableDevtool from 'disable-devtool';

DisableDevtool(options);

options中的参数与说明如下

interface IConfig {
    md5?: string; // 绕过禁用的md5值,详情见3.2,默认不启用绕过禁用
    url?: string; // 关闭页面失败时的跳转页面,默认值为localhost
    tkName?: string; // 绕过禁用时的url参数名称,默认为 ddtk
    ondevtoolopen?(type: DetectorType, next: Function): void; // 开发者面板打开的回调,启用时url参数无效,type 为监测模式,详见3.5, next函数是关闭当前窗口
    ondevtoolclose?(): void; // 开发者面板关闭的回调
    interval?: number; // 定时器的时间间隔 默认200ms
    disableMenu?: boolean; // 是否禁用右键菜单 默认为true
    stopIntervalTime?: number; // 在移动端时取消监视的等待时长
    clearIntervalWhenDevOpenTrigger?: boolean; // 是否在触发之后停止监控 默认为false, 在使用ondevtoolclose时该参数无效
    detectors?: Array<DetectorType>; // 启用的检测器 检测器详情见 3.5 默认为全部,建议使用全部
    clearLog?: boolean; // 是否每次都清除log
    disableSelect?: boolean; // 是否禁用选择文本 默认为false
    disableCopy?: boolean; // 是否禁用复制 默认为false
    disableCut?: boolean; // 是否禁用剪切 默认为false
    disablePaste: boolean; // 是否禁用粘贴 默认为false
    ignore?: (string|RegExp)[] | null | (()=>boolean); // 某些情况忽略禁用
    disableIframeParents?: boolean; // iframe中是否禁用所有父窗口
    timeOutUrl?: string; // 关闭页面超时跳转的url;
    rewriteHTML: string; // 检测到打开之后重写页面
}

enum DetectorType {
  Unknown = -1,
  RegToString = 0, // 根据正则检测
  DefineId, // 根据dom id检测
  Size, // 根据窗口尺寸检测
  DateToString, // 根据Date.toString 检测
  FuncToString, // 根据Function.toString 检测
  Debugger, // 根据断点检测,仅在ios chrome 真机情况下有效
  Performance, // 根据log大数据性能检测
  DebugLib, // 检测第三方调试工具 eruda 和 vconsole   
};

完结

以上的操作对一些大佬仍然是小巫见大巫,毕竟客户已经通过请求拿到了相关源码。

破解禁止调试方面

  1. 全局禁用debugger

  2. 局部禁用debugger

  3. 条件禁用debugger

  4. JS保存到本地,然后替换debugger字符

  5. 油猴插件,YYDS

油猴代码如下

  (function () {
    // 破解无限Debugger
    var constructorHook = constructor;
    Function.prototype.constructor = function (s) {
      if (s == "debugger") {
        return function () { }
      }
      return constructorHook(s);
    }
    const setInterval = window.setInterval;
    window.setInterval = function (fun, time) {
      // console.log(time, 'ddddd', fun.toString());
      if (fun && fun.toString) {
        var funString = fun.toString();
        if (funString.indexOf('debugger') > -1) return;
        if (funString.indexOf('window.close') > -1) return;
      }

      return setInterval(fun, time);
    }
  })()
    (() => {
      function ban() {
        setInterval(() => {
          debugger;
        }, 50);
      }
      try {
        ban();
      } catch (err) { }
    })();

原理就是替换,功能还可以根据我上面的方法做针对性修改。

未曾清贫难成人,不经打击老天真。 自古英雄出炼狱,从来富贵入凡尘。 醉生梦死谁成气,拓马长枪定乾坤。 挥军千里山河在,立名扬威传后人。