当你试图通过简单修改User-Agent字符串来伪装低版本浏览器时,现代指纹检测工具会在几毫秒内识破这种粗劣的把戏。真正的版本伪装是一门精细的科学,需要对Chromium每个版本引入的JavaScript、CSS和API特性有透彻理解。本文将为你呈现一份从76到115版本的完整特性差异清单,并揭示如何基于这些数据构建无懈可击的浏览器指纹。
去年某次渗透测试中,我遇到一个仅接受Chromium 89以下版本访问的金融系统。当我将浏览器版本号改为"89.0.4389.90"后,系统仍然拒绝访问。使用CreepJS检测后发现,我的"Chromium 89"暴露了92版本才引入的Array.at()方法——这就是典型的新版本特性污染。
现代浏览器指纹检测主要依赖三个维度的交叉验证:
以下是一个典型的版本检测逻辑在CreepJS中的实现:
javascript复制function checkVersionConsistency() {
// 检查JSON.rawJSON是否存在(115+特性)
if (typeof JSON.rawJSON !== 'undefined' && currentVersion < 115) {
return '版本伪造:检测到115+特性但报告低版本';
}
// 检查被移除的API
if (typeof Element.createShadowRoot !== 'undefined' && currentVersion >= 80) {
return '版本伪造:检测到已移除的旧API';
}
}
| 版本范围 | 新增特性示例 | 移除特性示例 |
|---|---|---|
| 76-78 | Promise.allSettled, Element.elementTiming |
- |
| 79-81 | ARIA相关属性全集, Intl.DisplayNames |
Document.registerElement |
| 85-86 | Promise.any, String.replaceAll |
Atomics.wake |
| 92-94 | Array.at, Error.cause, Object.hasOwn |
SharedArrayBuffer |
| 110-115 | JSON.rawJSON, 数组新方法 |
CanvasFilter |
关键注意事项:
Error.cause在94版暂时移除)markdown复制- 76-80:
* 新增:`backdrop-filter`, `overscroll-behavior`
* 移除:无显著移除
- 81-83:
* 新增:`color-scheme`, `contain-intrinsic-size`
* 行为变化:`image-orientation`语法变更
- 110+:
* 新增:`text-wrap`, `white-space-collapse`
* 移除:部分媒体查询参数
提示:CSS特性检测通常通过
CSS.supports()或计算样式检查实现,比JS检测更隐蔽
版本分水岭式的API变更最容易被检测到,以下是几个关键节点:
CompressionStream等流处理APIWeakRef等内存管理APIVideoFrame等)ViewTransition)javascript复制// 移除高版本API示例
if (typeof JSON.rawJSON !== 'undefined') {
delete JSON.rawJSON;
Object.defineProperty(JSON, 'rawJSON', { value: undefined });
}
javascript复制// 清理Array新方法
['toReversed', 'toSorted'].forEach(method => {
if (Array.prototype[method]) {
Object.defineProperty(Array.prototype, method, { value: undefined });
}
});
javascript复制// 处理不可配置属性
try {
delete window.CompressionStream;
} catch (e) {
window.CompressionStream = undefined;
}
虽然手动修改可行,但对于频繁切换版本的需求,建议使用以下策略:
javascript复制const versionFilter = new Proxy(window, {
get(target, prop) {
if (bannedFeatures115.includes(prop)) return undefined;
return Reflect.get(...arguments);
}
});
在某些特殊场景下,你可能需要实现"版本混合"效果——让浏览器在不同检测点呈现不同版本特征。这需要精细控制特性暴露的时机和顺序。
实现方案:
javascript复制// 动态版本切换示例
function setVersion(version) {
const features = versionFeatures[version];
features.removed.forEach(feat => {
if (feat in globalThis) {
globalThis[feat] = undefined;
}
});
}
在实际项目中,我发现最稳定的方案是选择3-5个连续小版本作为伪装目标,而不是跨越大版本区间。比如在106-109版本之间切换,比从115直接伪装到89要可靠得多。