1. 基于 MDN 和 Can I Use 设计环境检测项
无头浏览器检测
- 检测
window.chrome或window.__nightmare等特定无头浏览器属性。 - 检测
navigator.webdriver属性是否存在(无头浏览器通常会暴露此属性)。 - 检测
navigator.plugins和navigator.languages是否为空(无头浏览器通常不支持插件或多语言)。 - 检测
screen.width和screen.height是否符合正常浏览器的分辨率。
常规 DOM 检测
- 检测
document.createElement,window.addEventListener - 检测
document.documentElement.style是否可修改。 - 检测
window.localStorage和window.sessionStorage是否可用。
JSDOM 检测
- 检测
window.performance是否存在(JSDOM 可能不支持完整的 Performance API)。 - 检测
document.all的行为是否符合浏览器标准(JSDOM 可能不完全模拟)。 - 检测
window.alert或window.prompt是否被重写(JSDOM 可能不支持这些方法)。
其他检测
- 检测
WebGL支持情况(通过canvas.getContext('webgl'))。 - 检测
AudioContext是否可用。 - 检测
navigator.hardwareConcurrency是否符合正常范围。
2. 对检测项分类并通过 Babel 转换为 AST 节点
无头浏览器检测 AST 示例
const isHeadless = () => {
return navigator.webdriver !== undefined;
};
通过 Babel 转换为 AST 节点:
{
"type": "FunctionDeclaration",
"id": { "type": "Identifier", "name": "isHeadless" },
"body": {
"type": "BlockStatement",
"body": [
{
"type": "ReturnStatement",
"argument": {
"type": "BinaryExpression",
"operator": "!==",
"left": {
"type": "MemberExpression",
"object": { "type": "Identifier", "name": "navigator" },
"property": { "type": "Identifier", "name": "webdriver" }
},
"right": { "type": "Identifier", "name": "undefined" }
}
}
]
}
}
常规 DOM 检测 AST 示例
const isDOMSupported = () => {
return typeof document.createElement === 'function';
};
转换为 AST 节点后存储。
3. 随机提取每类检测项的 AST 节点
在每次生成代码时,从每类检测项中随机提取 N 个 AST 节点。例如:
- 从无头浏览器检测类中随机提取 2 个 AST 节点。
- 从常规 DOM 检测类中随机提取 3 个 AST 节点。
- 从 JSDOM 检测类中随机提取 1 个 AST 节点。
4. 组装 AST 节点并填充适配代码
将随机提取的 AST 节点组装成一个完整的函数,并填充额外的适配代码。例如:
const environmentCheck = () => {
const results = [];
results.push(isHeadless());
results.push(isDOMSupported());
results.push(isWebGLSupported());
return results.every(result => result === true);
};
将组装后的 AST 节点转换为最终的 JavaScript 代码。
5. 编译成 JSVM 字节码并存储到 Golang 代码中
使用 JSVM(JavaScript 虚拟机)将生成的 JavaScript 代码编译为字节码。例如:
在 Golang 中,通过 Wasm 加载 JS 虚拟机并执行字节码:
import (
"embed"
"github.com/robertkrimen/otto"
)
//go:embed bytecode.js
var bytecode embed.FS
func main() {
vm := otto.New()
script, _ := bytecode.ReadFile("bytecode.js")
vm.Run(script)
}
6. 使用 BrowserStack 验证混淆后的环境检测代码
将生成的环境检测代码部署到 BrowserStack 上,验证其在各种浏览器和设备上的可用性和兼容性。例如:
- 在 Chrome、Firefox、Safari、Edge 等主流浏览器上测试。
- 在移动设备(如 iOS 和 Android)上测试。
- 在无头浏览器(如 Puppeteer 和 Selenium)上测试,确保检测代码能够正确识别。
通过 BrowserStack 的自动化测试工具,生成测试报告并修复发现的兼容性问题