HTTP/3 测试 & 网络指纹实验室

两部分: 检测「当前浏览器 + 网络」能否与本站建立 HTTP/3 (QUIC) 连接(读 PerformanceResourceTiming.nextHopProtocol,h3=HTTP/3、h2=HTTP/2、http/1.1=HTTP/1.1); 采集本连接的服务端协议指纹(JA3/JA4、PeetPrint、Akamai HTTP/2、HTTP/3 指纹)——用于反欺诈研究:UA 声称的浏览器与真实指纹是否一致。

正在测试…首次请求通常走 h2;浏览器看到服务器广播的 h3(Alt-Svc)后,后续请求才会尝试 QUIC。请稍候几秒。

综合风险分(反欺诈)

正在综合四层信号评估…
综合四层(TLS 协议指纹 / 网络 TCP-IP / IP 信誉 / 客户端设备)信号,叠加历史关联——同设备指纹簇、同设备多 IP(代理轮换)、单位时间高频(velocity)、单 IP 多设备(设备农场)——给出可解释风险分。 → 打开关联层仪表盘(近 200 条访问 + 风险明细)。数据存于本机 SQLite,仅用于本实验演示。

HTTP/3 协商结果

最终协商协议
成功用上 HTTP/3 的比例
本页加载(导航)用的协议
服务器广播 h3 (Alt-Svc)检测中…
首次协商 h3 用了几次请求
平均往返(responseEnd-start)

逐次请求明细

#协议DNS连接TLSTTFB总计
DNS=域名解析;连接=TCP/QUIC 建连;TLS=加密握手;TTFB=首字节;单位 ms。h3/复用连接时部分阶段可能为 0。

服务端协议指纹(反欺诈)

正在从指纹服务(:8443)采集本连接的 TLS / HTTP2 / HTTP3 指纹…
怎么用于反欺诈:TLS 栈(JA3/JA4/PeetPrint)与 HTTP2/3 帧顺序由客户端底层库决定,伪造成本高。把这些 hash 与已知真实浏览器指纹库(如 tls.peet.ws)比对——若 UA 自称 Chrome,但 JA4/Akamai 指纹对应的是 Python/Go/curl,即高度可疑(脚本/爬虫/伪装)。这些指纹浏览器 JS 拿不到,必须服务端读原始 TLS/QUIC 帧,本页由独立指纹服务(TrackMe)在 :8443 提供。
▸ TLS 原始:密码套件 / 扩展 / PeetPrint
▸ HTTP/2 原始帧(SETTINGS / WINDOW_UPDATE / PRIORITY / 伪头顺序)

会话恢复 / QUIC 深度(A3 · A4)

正在读取会话恢复与 QUIC 参数…
会话恢复:客户端复用上次的 session ticket 时,ClientHello 会带 pre_shared_key(41), 里面的 ticket identity 是一个跨连接、跨 IP 都稳定的句柄 —— 它由 TLS 栈管理,JS 层改不掉, 比 canvas 更难规避。反过来,同一设备访问多次却从不复用,说明每次都是新容器/新配置(农场特征)。 QUIC 连接同样会在 ClientHello 里带 PSK(实测 Chromium 走 h3 时 pre_shared_keyused_0rtt 会同时出现)。首次访问因为还没有 ticket 可复用, 这一项显示"未复用"是正常的 —— 要看到复用,需要该浏览器此前访问过本站。
QUIC transport parameters参数顺序是客户端 QUIC 实现的指纹, 与 SETTINGS/Akamai 指纹互相独立。上游只给原始 hex,这里用 QUIC varint 在前端解出顺序与取值。

内核 RTO / 端点可达性(A5 · E1)

正在探测黑洞端口与备用端点…(约 12 秒)
SYN 重传曲线:向一个有包能进、但无人应答的端口(8445)发起连接, 客户端内核会自己重传 SYN。重传间隔暴露的是内核 RTO 实现,不同系统差别很大 —— Linux/Android 是 1s 起步每次翻倍,Windows 约 3s 起步且只重试两次,macOS/iOS 前几拍不退避。 这个信号在 JS 层完全改不掉(是内核行为),和 UA 自称的系统对不上就是硬矛盾。
端点可达性:同时打 :8443:2053 两个指纹端点。 2053 是 Cloudflare 常用端口,被运营商干扰的概率低于 8443 —— 两个都打才能看出 "哪个端点在哪家网络更可达",也验证主备切换是否真的生效。
IPv6 出口:很多代理/VPN 只接管 IPv4,IPv6 直接走原生链路 —— 这时 v4 显示代理出口、v6 却暴露真实地址,是经典的代理绕过。 双栈环境下二者属于不同 ASN 尤其可疑。
多锚点 RTT:同时测到国内/美国/新加坡几个位置确定的锚点, 最近的那个才是你物理上所在的区域 —— 与 IP 声称的位置对不上就是矛盾。
⚠️ 部分网络会对未监听端口代答 RST,那样客户端立刻放弃、不会重传 —— 此时本项会显示"未观察到重传",这是该网络的特性,不是探测失败。

真实地理位置研判(多源交叉)

正在多源交叉定位…
把所有带地理含义的信号放在一起投票,而不是只看 IP 归属。 客户端能改的(浏览器时区、语言)与改不了的(出口 IP、DNS 解析器归属、 ECS 子网、RTT 物理下界、Cloudflare 接入机房)分开计权 —— 后者对不上前者时,以后者为准。
RTT 能排除什么:光在光纤里约 200km/ms,所以 RTT 给出的是距离上界 —— "你不可能离锚点 X 超过 N 公里"。它只能排除"太远",不能排除"太近" (绕行与排队只会让 RTT 变大),所以单锚点无法收敛,要靠多个方向的锚点取交集。
能做到什么精度:城市级(靠 IP/DNS/ECS 三方交叉)到区域级(靠 RTT 排除)。 做不到街区级 —— 那需要 WiFi BSSID 查库,本项目主动不做(隐私)。

网络层 · TCP/IP 指纹与代理判定

正在读取本连接的 TCP/IP 指纹(需服务端从 SYN 抓取)…
怎么用于查代理:TTL/MSS/窗口/选项顺序由终结这条 TCP 连接的那台机器的操作系统内核决定。 ① MSS<1460(MTU<1500) → 链路上有隧道封装,疑似 VPN(WireGuard≈1420、OpenVPN≈1400)。 ② TTL 推断的系统 ≠ UA/TLS 声称的系统(如 UA 说 Windows、TTL 却是 *nix)→ 中间隔着 Linux 代理机,疑似代理/伪装。 透明代理(住宅代理/SOCKS)不改 TLS 指纹,但这一层的 MSS/OS 线索仍可能露馅。若本卡显示"不可用",通常是连接经了 NAT/负载均衡,原始 SYN 在本机不可见。

IP 信誉 / ASN(机房 vs 住宅)

正在查询 IP 归属(离线 ASN 库)…
怎么用于查代理:机房/托管 ASN(阿里云/腾讯云/AWS/OVH…)几乎不会是真实终端用户 → 命中即高度疑似 VPS/代理/爬虫;住宅代理则要靠 ASN + 上面的 TCP/MSS 线索综合判断。 地理↔时区不一致(IP 在美国、浏览器时区却是 Asia/Shanghai)也是代理的常见破绽。离线 ASN 库来自 iptoasn.com,无第三方请求。

DNS 行为(自建权威 DNS 实时观测)

正在触发一次唯一子域解析,观测你真正使用的递归解析器…(约需数秒)
并发向 16 个<随机>.d.h3.investigate.bio 触发解析,由本站自建权威 DNS 记录真正来查询的递归解析器 IPECS(原始值)。 为什么要发多个:解析器池会轮转,单次查询只落到其中一台 —— 实测同一网络下 12 个 token 能看到 5 台解析器, 其中一台还在完全不同的网段,只发 1 个有 4/5 概率漏掉它。解析器分布在多个 ISP 本身就是信号(DoH/分流/代理)。 解析器与你不在同网、或 ECS 子网与出口 IP 不符,常暗示公共 DNS / DoH / 代理;Cloudflare(1.1.1.1)默认不发 ECS(隐私)。这是浏览器完全拿不到、只能在权威侧观测的信号。

客户端设备指纹(高熵 · 设备关联)

正在采集浏览器高熵指纹…
怎么用于查同设备/批量注册:Canvas、WebGL(GPU 型号)、AudioContext、字体列表是高熵信号,组合后常接近唯一 → 即"设备指纹",能把多个账号关联到同一台机器。 服务端 TLS 指纹熵太低(百万人同为 Chrome/Win),做不到设备级关联,必须靠这一层。 三层交叉:WebGL 的 GPU 暗示的系统、UA 声称的系统、网络层 TTL 推断的系统三者应自洽——不一致往往是 anti-detect 浏览器 / 虚拟机 / 伪装。 此指纹在浏览器本地计算,随本页的其余检测结果一并上报给本站服务端用于关联分析,不发往第三方。

为什么把 Canvas 拆成多层:起因是有用户实测同型号手机、刷不同 ROM 后 Canvas 指纹会变, 但底层是同一颗芯片。原来一张画布混着矩形、文字、描边弧线一起算一个哈希,没法分辨"这次变化到底出在哪一层"。 现在拆成 几何(纯矢量路径+抗锯齿,不含文字/emoji)、文字·系统字体(多语种字体渲染)、 文字·内嵌字体emoji(彩色字体)、渐变合成(GPU 混合管线)独立哈希。 deviceId 现在只由"几何"层参与计算(连同 GPU/Audio/字体列表),文字与 emoji 层被排除在设备身份之外—— 这些层预期会随系统/ROM 的字体包更新而漂移,继续把它们混进身份哈希,只会让"同一台设备升级一次系统" 在系统里变成"凭空多出一台新设备"。

"文字·内嵌字体"这一层是怎么回事:第一轮上线后用户实测反馈"同 ROM 的两台手机四层完全一致, 换了 ROM 只有文字层不一样"——为了确认这到底是字体文件/版本的差异,还是渲染引擎本身的差异, 这一层改用本站自带、打包进页面的字体文件(Roboto Mono 拉丁字符子集,Apache 2.0 协议,内嵌为 data: URI,不发起任何网络请求)绘制同类文字,而不是调用系统装的字体。所有设备加载的字节完全相同—— 如果这一层也随 ROM 变,说明差异出在渲染引擎(hinting/抗锯齿实现);如果这一层不变而"系统字体"那层变, 说明差异就是系统字体文件本身随 ROM 升级了。只测拉丁字符:内嵌字体没有 CJK/emoji 字形,混进去 会触发系统字体回退,又把变量混回去了 —— 所以这一层的结论只能推广到拉丁文字部分。

"↳ 内嵌字体确认生效?"这一行是干什么的:字体加载是异步的,有可能悄悄失败又悄悄回退到系统字体 而不报错 —— 那样的话"文字·内嵌字体"这层其实又变回了"系统字体"的另一份拷贝,结论会整个反过来。 这一行不是"相信我加载成功了",而是独立测量:量出这台设备上 canvas 实际画出的 'M' 字符精确宽度, 跟这份字体文件自带的字形表算出的理论宽度(9.6016px,fonttools 读 hmtx 表核出的)做比对,还额外测了一次 "请求一个压根不存在的字体名"作为反例。两个条件都满足才算真生效:测出的宽度精确匹配理论值, 且明显不同于那个不存在字体的回退宽度。拿两台不同 ROM 的手机比较"文字·内嵌字体"哈希前,先看这两台 上这一行是不是都显示"✅ 确认生效"——如果任何一台显示"⚠️ 可疑",那台的对比结果不可信,不能拿来下结论。

✅ 2026-09 真机确认的结论:用户在同型号、不同 ROM 版本的手机上实测(两台"↳ 内嵌字体确认生效?" 均通过,结果可信)——几何 / emoji / 渐变合成 / 文字·内嵌字体这四层都不随 ROM 变,只有"文字·系统字体" 这一层会变。也就是说:Canvas 文字层随 ROM 漂移,根因是系统字体文件本身随系统更新换了版本, 不是渲染引擎(hinting/抗锯齿实现)本身发生了变化。这个结论已经写进 `docs/detection-capabilities.md` 并同步进了后端的观测规则措辞(只变系统字体层 vs 两层一起变,现在会给出不同的判断提示)。
⚠️ 这仍是小范围机型对照的结果,不代表对所有芯片/厂商/ROM 组合都成立 —— 后续遇到反例会回来更新。

客户端深度检测(机器人 / 反检测 / Client Hints)

正在做自动化/反检测/Client Hints 检测…
自动化检测navigator.webdriver、HeadlessChrome、Selenium/Puppeteer/Playwright 痕迹、权限矛盾等 → 脚本/爬虫反检测浏览器把 Canvas/WebGL/Audio 各跑两次——真浏览器结果恒定,注入随机噪声(Multilogin/GoLogin 等)则两次不同 → 批量注册工具Client Hints 的平台/架构与 UA 字符串、GPU、TCP 推断的系统应自洽,不符即伪装。

篡改检测(原生函数 / 描述符 / 跨 realm)

正在检查关键 API 是否被改写…
上一层"反检测浏览器"看的是值稳不稳(两次采样是否一致);这一层看的是有没有动过手脚的痕迹—— 即使伪造器把值做得很稳,只要它是用 JS 包了原生函数,Function.prototype.toString 就不再是 { [native code] }描述符异常抓"把 data property 改写成 getter"这类伪装 (常见于伪造 navigator.webdriver/hardwareConcurrency)。 跨 realm 用新建 iframe 取干净引用做对照,主 realm 被改过就会对不上。 字形度量比"数字体个数"熵高得多:同一串字在各字体下的精确宽高由字体文件与渲染引擎共同决定, 量化到 0.01px 后哈希——同机同浏览器必须完全可复现。 这些信号目前只观测不计分,等积累足够标注样本、算出各自的命中率与假阳性率后再赋权。

WebRTC IP 泄露(穿透 VPN/代理)

正在通过 STUN 收集 WebRTC 候选地址…
WebRTC 经 STUN 能拿到浏览器真实公网/局域 IP,可穿透 VPN/代理——与服务端看到的出口 IP 不符即暴露真实位置(经典查代理手段)。现代浏览器用 mDNS 隐藏局域 IP,但公网 srflx 候选仍可能泄露。

客户端·渲染 / 媒体 / 持久化

正在采集语音/编解码/emoji/WebGL/CSS/持久ID…
语音/emoji/编解码由 OS 决定 → 与 UA 声称系统交叉验证。持久 ID 冗余存于 localStorage+IndexedDB+cookie,清 cookie 也能重认——同一持久 ID 出现在不同设备指纹下 = 有人在清指纹/多开规避。纯本地,仅本实验演示。

客户端·行为与运行环境

正在观测交互与运行环境(约 6 秒;动动鼠标数据更全)…
无交互 + 机器人式鼠标(直线/匀速/瞬移)→ 脚本;指针/悬停与设备类型不符(移动 UA 却支持 hover)→ 伪装;CPU/计时/帧率异常(帧率<30、计时被粗化)→ VM/无头。行为需你在页面上动鼠标才有样本。

环境信息

测试时间
浏览器 / 版本
操作系统 / 平台
网络类型(如可读)
安全上下文 (HTTPS)
协议检测 API
页面地址
User-Agent

结果怎么读 / 排查

h3 出现 = 本浏览器与本网络成功建立了 QUIC 连接,UDP 443 全程通(客户端 + 网络 + 服务器都 OK)。

h2 始终 = 用不上 HTTP/3。本页测的是「到本服务器」的 h3,失败可能出在任一环节,请按下面排查: