浏览器客户端行为检测例子
原创2025年12月12日大约 5 分钟
浏览器客户端行为检测例子
想了解浏览器可以捕获到客户端的那些行为用来做更深入的分析
Html代码
index.html保存桌面浏览器运行
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>客户端行为综合检测</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, sans-serif;
padding: 20px;
background: #f9f9f9;
max-width: 1000px;
margin: 0 auto;
}
.section {
margin-top: 5px;
border-top: 2px solid #eee;
}
.risk-high { color: #d32f2f; font-weight: bold; }
.risk-medium { color: #f57c00; }
.risk-low { color: #388e3c; }
.info {
background: #f0f7ff;
padding: 10px;
margin: 6px 0;
border-left: 4px solid #2196f3;
border-radius: 4px;
}
#log {
width: 100%;
height: 250px;
background: white;
border: 1px solid #ccc;
padding: 10px;
overflow-y: auto;
margin-top: 5px;
font-size: 13px;
white-space: pre-wrap;
}
.counter { font-weight: bold; color: #c62828; }
/* ===== 行为状态横向布局 ===== */
.behavior-status {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 10px;
font-size: 14px;
}
.behavior-status > span {
white-space: nowrap;
}
button {
margin-top: 10px;
padding: 8px 16px;
background: #1976d2;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover { background: #1565c0; }
</style>
</head>
<body>
<p><strong>🔍 客户端行为检测:</strong>虚拟化环境 + 切屏/失焦行为</p>
<!-- 行为状态面板 -->
<div class="section">
<h3>👁️ 实时行为状态</h3>
<div class="behavior-status">
<span>页面可见性:<strong id="visibilityState">visible</strong></span>
<span>窗口聚焦:<strong id="focusState">true</strong></span>
<span>鼠标在页内:<strong id="mouseInState">未知</strong></span>
<span>失焦次数:<strong class="counter" id="blurCount">0</strong></span>
<span>隐藏次数:<strong class="counter" id="hiddenCount">0</strong></span>
<span>最长离开:<strong id="maxHiddenTime">0 秒</strong></span>
</div>
</div>
<!-- 环境风险 -->
<div class="section">
<h3>⚠️ 高风险虚拟化特征</h3>
<div id="highRisk"></div>
</div>
<button onclick="clearLog()">清空日志</button>
<div id="log"></div>
<!-- 详细信息 -->
<div class="section">
<h3>ℹ️ 详细环境指纹</h3>
<div id="details"></div>
</div>
<script>
// ========== 全局变量 ==========
let blurCount = 0;
let hiddenCount = 0;
let maxLeaveDuration = 0;
let leaveStartTime = null; // 统一记录离开开始时间
const logEl = document.getElementById('log');
// ========== 日志函数 ==========
function log(msg) {
const time = new Date().toLocaleTimeString();
logEl.innerHTML += `[${time}] ${msg}\n`;
logEl.scrollTop = logEl.scrollHeight;
}
function updateBehaviorStatus() {
document.getElementById('visibilityState').textContent = document.visibilityState;
const hasFocus = document.hasFocus();
document.getElementById('focusState').textContent = String(hasFocus);
}
// 判断是否处于“离开”状态:页面隐藏 或 窗口失焦
function isUserAway() {
return document.visibilityState === 'hidden' || !document.hasFocus();
}
// 开始离开计时(防重复)
function startLeaveTimer() {
if (leaveStartTime === null && isUserAway()) {
leaveStartTime = Date.now();
log('⏳ 用户离开页面(隐藏或失焦),开始计时...');
}
}
// 结束离开计时
function endLeaveTimer() {
if (leaveStartTime !== null && !isUserAway()) {
const durationSec = Math.round((Date.now() - leaveStartTime) / 1000);
if (durationSec > maxLeaveDuration) {
maxLeaveDuration = durationSec;
document.getElementById('maxHiddenTime').textContent = `${durationSec} 秒`;
}
log(`✅ 用户返回,本次离开时长:${durationSec} 秒`);
leaveStartTime = null;
}
}
// ========== 行为监听 ==========
// 页面可见性变化
document.addEventListener('visibilitychange', () => {
updateBehaviorStatus();
if (document.visibilityState === 'hidden') {
hiddenCount++;
document.getElementById('hiddenCount').textContent = hiddenCount;
log('⚠️ 页面变为 HIDDEN(可能被切屏/最小化)');
}
// 触发离开/返回判断
if (isUserAway()) {
startLeaveTimer();
} else {
endLeaveTimer();
}
});
// 窗口失焦
window.addEventListener('blur', () => {
blurCount++;
document.getElementById('blurCount').textContent = blurCount;
log('⚠️ WINDOW 失去焦点(blur)— 可能因点击本地程序、切换窗口等');
updateBehaviorStatus();
startLeaveTimer(); // 可能进入离开状态
});
// 窗口聚焦
window.addEventListener('focus', () => {
log('✅ WINDOW 重新获得焦点(focus)');
updateBehaviorStatus();
endLeaveTimer(); // 尝试结束离开
});
// 鼠标进出
document.addEventListener('mouseenter', () => {
document.getElementById('mouseInState').textContent = '是';
log('🖱️ 鼠标进入页面区域');
});
document.addEventListener('mouseleave', () => {
document.getElementById('mouseInState').textContent = '否';
log('🖱️ 鼠标离开页面区域(注意:仅移出不等于失焦)');
});
// ========== 环境检测函数(保持不变)==========
function detectWebGL() {
let info = [], risks = [];
try {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (gl) {
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
if (debugInfo) {
const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) || 'unknown';
const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) || 'unknown';
info.push(`WebGL Renderer: ${renderer}`);
info.push(`WebGL Vendor: ${vendor}`);
const lowerRenderer = renderer.toLowerCase();
const lowerVendor = vendor.toLowerCase();
if (lowerRenderer.includes('vmware') || lowerRenderer.includes('svga')) {
risks.push('检测到 VMware 虚拟 GPU (SVGA3D)');
} else if (lowerRenderer.includes('virtualbox') || lowerVendor.includes('chromium')) {
risks.push('检测到 VirtualBox 虚拟 GPU (Chromium)');
} else if (lowerVendor.includes('microsoft basic') || lowerRenderer.includes('basic render')) {
risks.push('检测到 Microsoft Basic Render Driver(Hyper-V/远程桌面)');
} else if (lowerRenderer.includes('llvmpipe') || lowerRenderer.includes('software')) {
risks.push('使用软件渲染(常见于无 GPU 的虚拟机)');
}
}
} else {
info.push('WebGL 不可用');
risks.push('WebGL 不可用(真实设备通常支持)');
}
} catch (e) {
info.push('WebGL 检测出错: ' + e.message);
}
return { info, risks };
}
function detectScreen() {
const info = [];
const risks = [];
const cd = screen.colorDepth;
const w = screen.width;
const h = screen.height;
info.push(`分辨率: ${w}x${h}, 色深: ${cd} bit`);
if (cd <= 24) {
risks.push('屏幕色深 ≤24 bit(典型远程桌面/RDP 特征)');
}
return { info, risks };
}
function detectSystem() {
const info = [];
const risks = [];
const ua = navigator.userAgent;
const cores = navigator.hardwareConcurrency || 'unknown';
const memory = navigator.deviceMemory || 'unknown';
info.push(`UserAgent: ${ua}`);
info.push(`CPU 核心数: ${cores}`);
info.push(`估算内存 (GB): ${memory}`);
if (ua.includes('HeadlessChrome')) risks.push('检测到 Headless Chrome');
if (navigator.webdriver) risks.push('navigator.webdriver=true(自动化工具)');
if (typeof cores === 'number' && cores <= 2) risks.push('CPU 核心数 ≤2(轻量虚拟机配置)');
return { info, risks };
}
function detectNetwork() {
const info = [];
const risks = [];
const ips = new Set();
try {
const pc = new (window.RTCPeerConnection || window.webkitRTCPeerConnection)();
pc.createDataChannel('');
pc.onicecandidate = (e) => {
if (e.candidate) {
const match = e.candidate.candidate.match(/(\d+\.\d+\.\d+\.\d+)/);
if (match) {
const ip = match[1];
if (!ips.has(ip)) {
ips.add(ip);
info.push(`本地 IP: ${ip}`);
if (ip.startsWith('192.168.56.')) risks.push('IP 属于 VirtualBox Host-Only 网段');
else if (ip.startsWith('192.168.220.')) risks.push('IP 属于 VMware NAT 网段');
else if (ip.startsWith('10.0.2.')) risks.push('IP 属于 VirtualBox NAT 网段');
}
}
}
};
pc.createOffer().then(offer => pc.setLocalDescription(offer));
setTimeout(() => pc.close(), 2000);
} catch (e) {
info.push('WebRTC 不可用');
}
if (ips.size === 0) info.push('未获取到本地 IP(WebRTC 可能被禁用)');
return { info, risks };
}
function detectSensors() {
const info = [];
const risks = [];
if (!('Accelerometer' in window)) {
risks.push('缺少设备传感器(常见于虚拟机)');
}
info.push(`Battery API 支持: ${'getBattery' in navigator ? '是' : '否'}`);
return { info, risks };
}
// ========== 主检测逻辑 ==========
function runEnvironmentDetection() {
const allInfo = [];
const highRisks = [];
const tests = [detectSystem, detectScreen, detectWebGL, detectNetwork, detectSensors];
tests.forEach(test => {
const res = test();
allInfo.push(...res.info);
highRisks.push(...res.risks);
});
const riskEls = highRisks.map(r => `<div class="info risk-high">• ${r}</div>`).join('');
document.getElementById('highRisk').innerHTML =
highRisks.length > 0 ? riskEls : '<div class="info">✅ 未发现高风险虚拟化特征</div>';
document.getElementById('details').innerHTML =
allInfo.map(i => `<div class="info">${i}</div>`).join('');
}
// ========== 初始化 ==========
updateBehaviorStatus();
log('监听页面行为(切屏/失焦/鼠标) + 检测虚拟化环境特征...');
runEnvironmentDetection();
function clearLog() {
logEl.innerHTML = '';
blurCount = 0;
hiddenCount = 0;
maxLeaveDuration = 0;
leaveStartTime = null;
document.getElementById('blurCount').textContent = '0';
document.getElementById('hiddenCount').textContent = '0';
document.getElementById('maxHiddenTime').textContent = '0 秒';
}
</script>
</body>
</html>