Pārlūkot izejas kodu

!252 feat: 添加开发者工具保护功能,防止调试
Merge pull request !252 from mubai576/dev

疯狂的狮子Li 4 mēneši atpakaļ
vecāks
revīzija
f9c3958d5d
2 mainītis faili ar 164 papildinājumiem un 0 dzēšanām
  1. 6 0
      src/main.ts
  2. 158 0
      src/utils/devtools-protection.ts

+ 6 - 0
src/main.ts

@@ -28,6 +28,9 @@ import ElementIcons from '@/plugins/svgicon';
 // permission control
 import './permission';
 
+// 开发者工具保护
+import { initDevToolsProtection } from '@/utils/devtools-protection';
+
 // 国际化
 import i18n from '@/lang/index';
 
@@ -55,3 +58,6 @@ app.use(plugins);
 directive(app);
 
 app.mount('#app');
+
+// 初始化开发者工具保护(仅生产环境)
+initDevToolsProtection();

+ 158 - 0
src/utils/devtools-protection.ts

@@ -0,0 +1,158 @@
+/**
+ * 开发者工具保护
+ * 检测开发者工具是否打开,如果打开则循环执行 debugger 阻止调试
+ */
+
+// 检测开发者工具是否打开
+function detectDevTools(): boolean {
+  try {
+    // 方法1: 检测窗口尺寸差异(最可靠的方法)
+    const widthThreshold = 160; // 开发者工具最小宽度
+    const heightThreshold = 160; // 开发者工具最小高度
+
+    const widthDiff = window.outerWidth - window.innerWidth;
+    const heightDiff = window.outerHeight - window.innerHeight;
+
+    if (widthDiff > widthThreshold || heightDiff > heightThreshold) {
+      return true;
+    }
+
+    // 方法2: 检测 debugger 执行时间(最准确的方法)
+    const start = performance.now();
+    debugger; // 这个 debugger 用于检测,不会被移除
+    const end = performance.now();
+    const timeDiff = end - start;
+
+    // 如果 debugger 被跳过(开发者工具关闭),时间差会很小(通常 < 1ms)
+    // 如果 debugger 暂停(开发者工具打开),时间差会很大(通常 > 100ms)
+    // 降低阈值以提高检测灵敏度
+    if (timeDiff > 10) {
+      return true;
+    }
+
+    // 方法3: 检测控制台对象
+    let devtoolsDetected = false;
+    const element = document.createElement('div');
+    Object.defineProperty(element, 'id', {
+      get: function () {
+        devtoolsDetected = true;
+        return '';
+      }
+    });
+
+    // 使用 console 来触发 getter(仅在开发者工具打开时)
+    try {
+      console.log(element);
+      console.clear();
+    } catch (e) {
+      // 忽略错误
+    }
+
+    if (devtoolsDetected) {
+      return true;
+    }
+
+    // 方法4: 检测控制台是否被重写(开发者工具打开时)
+    const devtoolsRegex = /./;
+    // @ts-expect-error - 动态添加属性
+    devtoolsRegex.toString = function () {
+      // @ts-expect-error - 动态添加属性
+      this.opened = true;
+    };
+    console.log('%c', devtoolsRegex);
+    // @ts-expect-error - 检查动态添加的属性
+    if (devtoolsRegex.opened) {
+      return true;
+    }
+  } catch (e) {
+    // 如果检测过程中出错,默认返回 false
+    return false;
+  }
+
+  return false;
+}
+
+// 开发者工具保护主函数
+export function initDevToolsProtection(): void {
+  // 可以通过环境变量控制是否启用
+  // 生产环境默认启用,开发环境可以通过 VITE_ENABLE_ANTI_DEBUG=true 来启用测试
+  const isProduction = import.meta.env.MODE === 'production';
+  const enableAntiDebug = import.meta.env.VITE_ENABLE_ANTI_DEBUG === 'true' || isProduction;
+
+  if (!enableAntiDebug) {
+    return;
+  }
+
+  let devToolsOpen = false;
+  let debuggerInterval: number | null = null;
+
+  // 立即执行一次检测
+  const initialCheck = detectDevTools();
+  if (initialCheck) {
+    devToolsOpen = true;
+    debuggerInterval = window.setInterval(() => {
+      debugger; // 循环执行 debugger
+    }, 50); // 更频繁的 debugger,每 50ms 一次
+  }
+
+  // 循环检测开发者工具(更频繁的检测)
+  const checkInterval = setInterval(() => {
+    const isOpen = detectDevTools();
+
+    if (isOpen && !devToolsOpen) {
+      // 开发者工具刚打开
+      devToolsOpen = true;
+
+      // 开始循环执行 debugger(更频繁)
+      if (debuggerInterval === null) {
+        debuggerInterval = window.setInterval(() => {
+          debugger; // 循环执行 debugger
+        }, 50); // 每 50ms 执行一次,更激进
+      }
+    } else if (!isOpen && devToolsOpen) {
+      // 开发者工具关闭了
+      devToolsOpen = false;
+
+      // 停止循环 debugger
+      if (debuggerInterval !== null) {
+        clearInterval(debuggerInterval);
+        debuggerInterval = null;
+      }
+    }
+  }, 500); // 每 500ms 检测一次,更频繁
+
+  // 页面卸载时清理
+  window.addEventListener('beforeunload', () => {
+    clearInterval(checkInterval);
+    if (debuggerInterval !== null) {
+      clearInterval(debuggerInterval);
+    }
+  });
+
+  // 额外的检测:监听窗口大小变化
+  let lastWidth = window.innerWidth;
+  let lastHeight = window.innerHeight;
+
+  window.addEventListener('resize', () => {
+    const currentWidth = window.innerWidth;
+    const currentHeight = window.innerHeight;
+
+    // 如果窗口尺寸变化很大,可能是开发者工具打开/关闭
+    if (Math.abs(currentWidth - lastWidth) > 200 || Math.abs(currentHeight - lastHeight) > 200) {
+      // 重新检测
+      const isOpen = detectDevTools();
+      if (isOpen && !devToolsOpen) {
+        devToolsOpen = true;
+        if (debuggerInterval === null) {
+          debuggerInterval = window.setInterval(() => {
+            debugger; // 循环执行 debugger
+          }, 50); // 更频繁的 debugger
+        }
+      }
+    }
+
+    lastWidth = currentWidth;
+    lastHeight = currentHeight;
+  });
+}
+