lib/fingerprint 用于生成可注入到页面的新文档脚本,帮助 rod 在授权测试、兼容性研究、浏览器行为回放里统一定制浏览器暴露面的指纹值。
当前支持的表面:
navigator、navigator.userAgentData 与硬件相关字段(如 oscpu、cpuClass、vendorSub、productSub、pdfViewerEnabled)screen 与 window.devicePixelRatioIntl 的 resolvedOptions(含 calendar、numberingSystem、hourCycle)与 Date.prototype.getTimezoneOffsetnavigator.permissions 与 Notificationnavigator.mediaDevicesnavigator.plugins 与 navigator.mimeTypesdocument.fonts.check、queryLocalFonts 与 CanvasRenderingContext2D.measureTextnavigator.getBatterynavigator.connection / navigator.mozConnection / navigator.webkitConnection(含真实 EventTarget listener 存储)speechSynthesis.getVoices()AudioContextcanvasWebGL(含 extensions、parameters 深度覆盖)RTCPeerConnection WebRTC 泄露防护(disable / relay 模式)navigator.storage.estimate() StorageManagerperformance.now() / Date.now() 精度降噪Function.prototype.toString 伪装(反检测基础设施)Object.getOwnPropertyDescriptor 防御(反检测基础设施)模块内部已经按职责拆为:
types.go:公开配置 structvalidate.go:参数校验与 enabled 判定source.go:payload 序列化与脚本拼接script_common.go:共享 runtime 原语、toString 伪装、OwnPropertyDescriptor 防御script_navigator.go:navigator / permissions / notificationscript_environment.go:fonts / intl / battery / network / screen / storageManager / timingscript_media.go:mediaDevices / plugins / mimeTypes / audioContext / speechSynthesisscript_rendering.go:canvas / webglscript_webrtc.go:WebRTC 泄露防护script_worker.go:Worker(classic + module)内 navigator 一致性script_frame.go:iframe contentWindow navigator 一致性根层推荐优先通过 rod.Page.WithFingerprint 或 rod.Page.MustWithFingerprint 使用;SetFingerprint / MustSetFingerprint 仍保留给需要手动管理生命周期的底层场景:
webdriver := false
page.MustWithFingerprint(&rod.Fingerprint{
Navigator: &rod.NavigatorFingerprint{
UserAgent: rod.Ptr("RodAgent/1.0"),
Platform: rod.Ptr("RodOS"),
Language: rod.Ptr("zh-CN"),
Languages: rod.Ptr([]string{"zh-CN", "zh"}),
OSCPU: rod.Ptr("RodOSCPU"),
CPUClass: rod.Ptr("x86"),
HardwareConcurrency: rod.Ptr(0),
DeviceMemory: rod.Ptr(0.0),
MaxTouchPoints: rod.Ptr(0),
WebDriver: &webdriver,
UAData: &rod.NavigatorUADataFingerprint{
Brands: rod.Ptr([]rod.NavigatorBrandFingerprint{{Brand: "Rod", Version: "1"}}),
FullVersionList: rod.Ptr([]rod.NavigatorBrandFingerprint{{Brand: "Rod", Version: "1.0.0.0"}}),
Platform: rod.Ptr("RodOS"),
},
},
Intl: &rod.IntlFingerprint{
TimeZone: rod.Ptr("Asia/Shanghai"),
OffsetMinutes: rod.Ptr(-480),
Calendar: rod.Ptr("gregory"),
NumberingSystem: rod.Ptr("latn"),
HourCycle: rod.Ptr("h23"),
},
Fonts: &rod.FontsFingerprint{
Families: rod.Ptr([]string{"Rod Sans", "Rod Mono"}),
WidthMultipliers: rod.Ptr(map[string]float64{
"Rod Sans": 1.5,
}),
},
Notification: &rod.NotificationFingerprint{
Permission: rod.Ptr("denied"),
},
MediaDevices: &rod.MediaDevicesFingerprint{
Devices: rod.Ptr([]rod.MediaDeviceFingerprint{
{
DeviceID: "rod-mic-1",
Kind: "audioinput",
Label: "Rod Mic",
},
}),
},
Battery: &rod.BatteryFingerprint{
Level: rod.Ptr(0.42),
},
NetworkInformation: &rod.NetworkInformationFingerprint{
EffectiveType: rod.Ptr("4g"),
Type: rod.Ptr("wifi"),
},
WebGL: &rod.WebGLFingerprint{
Vendor: rod.Ptr("Google Inc. (NVIDIA)"),
Renderer: rod.Ptr("ANGLE (NVIDIA GeForce RTX 3060)"),
Extensions: rod.Ptr([]string{
"ANGLE_instanced_arrays",
"EXT_blend_minmax",
"WEBGL_debug_renderer_info",
}),
Parameters: rod.Ptr(map[string]any{
"7938": "WebGL 1.0 (OpenGL ES 2.0 Chromium)",
}),
},
WebRTC: &rod.WebRTCFingerprint{
Mode: rod.Ptr("relay"), // "disable" 完全禁用 | "relay" 强制中继
PublicIP: rod.Ptr("1.2.3.4"), // 仅 relay 模式下替换 SDP 中的 IP
},
SpeechSynthesis: &rod.SpeechSynthesisFingerprint{
Voices: rod.Ptr([]rod.SpeechVoiceFingerprint{
{Name: "Microsoft Huihui", Lang: "zh-CN", LocalService: rod.Ptr(true)},
}),
},
StorageManager: &rod.StorageManagerFingerprint{
Quota: rod.Ptr(int64(2147483648)),
Usage: rod.Ptr(int64(1048576)),
},
Timing: &rod.TimingFingerprint{
Precision: rod.Ptr(100.0), // 微秒量化精度
Jitter: rod.Ptr(5.0), // 最大抖动微秒
},
}, func() {
page.MustNavigate("https://example.com").MustWaitLoad()
})
如果需要直接使用底层包,可调用:
fingerprint.ApplySource(id, cfg)fingerprint.RemoveSource(id)fingerprint.Ptr(v)这样可以把脚本注入到你自己的 CDP / browser orchestration 流程里。
lib/fingerprint 现在已经按 presence-driven pointer-style 收口主要 surface:nil 表示不覆盖,非 nil 则即便是 ""、[]、{}、0、false 也会被显式注入。需要表达空值时,不要依赖 Go 零值,直接传 pointer-style 字段。当前已覆盖:
navigator.* 与 navigator.userAgentData.*screen.* 与 devicePixelRatioIntl.*permissions / notificationmediaDevices / plugins / mimeTypes / fontsbattery / networkInformationaudioContext / canvas / webgl / webrtc / speechSynthesisstorageManager / timing