你打开 VPN,挑了一台阿姆斯特丹的服务器,然后打开一个网页。在你试过的每一个 IP 检测网站上,你的 IP 地址都显示为荷兰。然而结账时却多出了一道额外的验证步骤,流媒体的片库依旧不对,或者一次登录触发了一封“新设备”提醒邮件。出卖你的东西只有一行 JavaScript:Intl.DateTimeFormat().resolvedOptions().timeZone。
这个调用返回的是你操作系统所设置的时区,而 VPN 对它没有丝毫影响。你的数据包如今确实来自阿姆斯特丹;你的浏览器却仍然兴高采烈地上报 America/New_York。本页上的小工具跑的正是欺诈脚本会做的那套比对:查出你的 IP 地址所对应的时区,读取你的浏览器上报的时区,然后检查两者是否一致。
同一个问题,两个答案
第一个答案来自网络。网站看到你连接时使用的 IP,然后到地理位置数据库里去查:ipinfo.io、MaxMind 以及它们的竞争对手,都会连同位置一起返回一个时区。开着 VPN 时,这个答案指向的是出口服务器:经由阿姆斯特丹连接,数据库就会说 Europe/Amsterdam。这些数据库是如何构建的、它们定位你的街道地址时能错得多离谱,我们在 IP 地理定位文章 里讲过。但在时区这个粒度上,它们几乎从不出错。
第二个答案来自你的操作系统。早在九十年代,JavaScript 就能通过 new Date().getTimezoneOffset() 读到本地与 UTC 的时差,而现代浏览器还会通过 Intl API 把完整的 IANA 时区名双手奉上。没有权限弹窗,不需要用户操作,任何隐私面板里都不会留下记录。它被当作再普通不过的元数据,和你的屏幕尺寸归在同一类。
198.51.100.7 地理位置数据库 Europe/AmsterdamIntl.DateTimeFormat() America/New_YorkEurope/Amsterdam ≠ America/New_York —
一次字符串比较就足以识破,此时你甚至还没点过任何东西。比对这两个答案毫无成本,所以只要有理由,谁都会做:支付欺诈评分、流媒体地区限制、广告反作弊过滤、账号安全系统,还有那些本来就在跑着十几项一致性检查的反机器人堆栈。
为什么 VPN 解决不了这件事
VPN 会加密你的流量,并换掉服务器所看到的 IP 地址。它的全部职责就到此为止。你的时区从不经过隧道传输,因为它压根不需要传输。它躺在你的操作系统设置里,浏览器在本地读取它,然后交给任何一个来问的脚本。
网站得知的并不是你的时钟显示几点,而是时区标识符。America/New_York 是一个位置声明,精确到地球上的一条纵向条带,而且它就明晃晃地摆在 navigator.language 和 Accept-Language 请求头旁边,后两者 对你住在哪里做出的是同一类声明。
平心而论,单凭一次不匹配什么也证明不了。有人带着还以为自己在家的笔记本飞来飞去,也有远程工作者故意保持团队所在地的时区。检测系统清楚这些,所以不匹配只会计入风险评分,而不会直接触发封禁。可分数是会累加的:时区不匹配,加上一个数据中心 IP,再加上一次 WebRTC 泄露,就不再有任何含糊,而且每一个信号都会让下一个信号的分量变得更重。
半吊子伪装的陷阱
显而易见的补救办法是连时区一起撒谎,市面上也确实堆着一堆干这个的扩展。它们大多会覆盖 Intl.DateTimeFormat,让 resolvedOptions().timeZone 返回你配置的任意值。问题在于,你的浏览器会在不止一个地方宣告它的时区:
new Date().getTimezoneOffset()通过一条完全不同的代码路径,报告你的时钟落后 UTC 多少分钟。Date.prototype.toString()会把时区用文字拼写出来:“GMT-0400 (Eastern Daylight Time)”。- 对一年中任意一天做日期格式化,会暴露你的夏令时规则,而这些规则正是一个时区的身份特征之一。
固定不变的时差并不是一个时区。阿姆斯特丹在七月是 UTC+2,一月却是 UTC+1,而且它拨钟的日期和纽约不一样:欧盟在三月最后一个星期日改时间,美国要早上两三个星期。脚本可以问出你在一月一日和七月一日的时差各是多少,再核对这一对数值是否与你声称的时区吻合。一个把时差全年钉死在一个值上的伪装,与地球上任何会拨钟的地方都对不上号,更不用说它口口声声自称的阿姆斯特丹了。
只要漏掉其中任何一条,浏览器就会开始自相矛盾:
Europe/Amsterdam America/New_York UTC−4 这个陷阱还有第二层。被覆盖过的 Intl.DateTimeFormat,在脚本检视它的源码时已经不像原生函数了。这正是揪出隐身插件的那种“补丁函数”破绽,我们在 机器人检测文章 里逐步演示过。一次干净的不匹配说的是“多半在用 VPN”。一个被打过补丁的 API 说的却是“这个人正在主动篡改浏览器”,而每一套认真的评分系统都会给后者标上更高的价码。
到底该怎么做
- 先测试,再信任。 本页上的小工具此刻就在拿你浏览器的时区和 IP 的时区做比对,而 完整浏览器扫描 会把它和 WebRTC、平台与指纹检查一并跑完。开着 VPN 测一遍。如果这个小工具标记了你,那么每一个欺诈脚本也都会。
- 让你的时钟跟着 VPN 走。 最无聊的修法就是最扎实的修法:连接之前,把操作系统的时区调成出口城市所在的时区。没有任何东西可供检测,因为没有任何东西是假的:每一个 API 都从同一个来源上报同一个时区。隐私派的替代方案是 Tor Browser,它对所有人都上报 UTC;你的真实时区确实藏住了,代价是看起来完全就是 Tor Browser。
- 如果你运营着多个身份,就别再手动干这件事了。 跨地区管理账号,意味着每个配置文件都需要自己的 IP、时区、语言和指纹,彼此吻合,而且每一次会话都得如此。这种繁琐的对账工作,正是防关联(anti-detect)浏览器要替你自动化的:Incogniton 会根据每个配置文件的代理 IP 推导出它的时区,让本文所说的这两个答案从一开始就没有机会互相矛盾。
时区检查是脚本能跑的最廉价的地理位置交叉核对,这也正是它无处不在的原因。花三十秒用上面的小工具测一测,你就知道自己站在它的哪一边了。