OONI 错误测量的识别方法与匿名凭证
很多人靠 OONI 的公开数据集判断某个网站在某个国家能否访问,anoni.net 的 OONI 观测覆盖率也建立在同一份数据上。数据集开放任何人投稿,有人送入假数据,或设备设置错误产生误导性的记录,整份数据的可信度都会被稀释。OONI 在一篇工程文章1里说明他们如何找出错误的测量,以及正在导入生产环境的匿名凭证(anonymous credentials)系统如何在不保存个人数据的前提下挡下滥用。不留个人数据也能评估测量可信度的做法,本身就是值得参考的隐私工程范例,后面的匿名凭证系统的运作方式一节会回头谈。
本文是 anoni.net 对 OONI 工程文章 From Heuristics to Anonymous Credentials: Assessing OONI's Approach to Bad Measurements(2026-07-06)的导读与摘要,依原文的章节整理重点,并非逐字翻译。原文另有约 20 张统计图与多份完整数据表,数据细节请直接读原文。
OONI(Open Observatory of Network Interference,开放网络干扰观测站)是全球性的网络审查观测项目,OONI Probe 依一份网站清单逐一连接,回报每个网站在当地能否访问,结果一律进入公开数据集。任何人都能下载数据做分析,同样地,任何人也都能送数据进来。原文要回答的问题,就是在开放投稿的前提下,如何辨认并过滤质量有问题的测量。
原文的架构
OONI 先用手上既有的数据建立一套辨认错误测量的基准,再评估新的匿名凭证系统能把基准往上推多少。启发式(heuristic)是一组简单、成本低的判断规则,不追求百分之百准确,先用几条经验法则把可疑的测量筛出来。全文分成三块,先用简单规则检查既有数据能找出多少问题(既有启发式与四类发现),再提出更高级的规则(新启发式),最后处理找到错误数据之后的应对机制(缓解策略与匿名凭证)。
既有指标与四个检查角度
原文的 Existing metrics and heuristics 一节不动用任何新技术,只检查 OONI 现在就收得到的数据能否认出错误的测量。OONI 挑了四个不需要牺牲用户隐私的检查角度,分别是 IP 地理位置的错配、测量数量的暴增、时间戳的不一致,以及操作系统与版本信息的矛盾。每个角度都附了但书(caveat),说明该信号在哪些情况下会误判。例如探针(probe)内置的 GeoIP 数据库可能过期,probe_cc(探针回报的国家代码)本来就可能跟真实 IP 对不上,分析时要先滤掉正常的误差。四个角度与各自的但书,构成后面所有发现的方法论基础。
四类异常的实际发现
IP 地理位置的错配
OONI 在 2025 年 3 月 19 到 21 日,于探针调用 /api/v1/check-in 端点时记录 log,比对探针自己回报的国家代码、ASN(自治系统编号)与收集端看到的真实出口 IP。16,139 条样本里有 1,196 条对不上,约 7.41%。原文列出最常见的 10 组国家代码错配:
| 回报国家代码 | 真实 IP 国家代码 | 条数 |
|---|---|---|
| US 美国 | CA 加拿大 | 89 |
| CA 加拿大 | RU 俄罗斯 | 49 |
| CZ 捷克 | US 美国 | 43 |
| BS 巴哈马 | US 美国 | 36 |
| CA 加拿大 | US 美国 | 30 |
| CA 加拿大 | SG 新加坡 | 30 |
| CZ 捷克 | GB 英国 | 25 |
| CA 加拿大 | KH 柬埔寨 | 18 |
| AU 澳大利亚 | KH 柬埔寨 | 18 |
| US 美国 | DE 德国 | 16 |
错配的来源绝大多数是 VPN,出现最多的网络是 Datacamp、Cloudflare、M247 这些已知的 VPN 机房。回报加拿大、真实 IP 在俄罗斯的 49 条全部来自 Cloudflare,对应的是使用 WARP 这类 VPN 的用户。表格里多数组合都属于同一种情况,探针回报自己在 A 国,流量却从 B 国的 VPN 出口送出。原文没有找到明显可归因于恶意篡改或探针设置错误的错配。
测量数量的暴增
OONI 统计每个探针在 1 分钟内产出的测量条数,平均是 8 条,99 百分位是 54 条。筛出每分钟超过 200 条的极端案例后,找到一个名为 ooniprobe-react-os、并非 OONI 官方发行版本的客户端。它只送 probe_cc = CN(中国)的数据,以每分钟 200 条(相当于每秒 3 条)的速度送出 web_connectivity 测量,速率远超正常范围。更反常的是,ooniprobe-react-os 送出测量的速度比同地区其他探针还快,量这么大却没有出现对应的网络瓶颈。另一个案例是缅甸在 2025 年 1 月 6 日出现的阵发性暴增。
时间戳的不一致
OONI 比对测量开始时间 measurement_start_time 与 measurement_uid 内含的时间戳,找出上传太晚或时间落在未来的记录。2025 年 3 月 2 日到 4 月 1 日的 3,440 多万条测量里,只有 0.82% 有时间异常,多数落在过去,集中在 Linux。原文依平台拆解如下,Linux 的异常率 2.16% 明显高于其他平台:
| 平台 | 过去异常(>1h) | 未来异常(>1h) | 异常合计 | 该平台总量 | 异常率 |
|---|---|---|---|---|---|
| ios | 2,375 | 0 | 2,375 | 240,843 | 0.99% |
| windows | 34,192 | 24,938 | 59,130 | 10,503,040 | 0.56% |
| android | 21,132 | 5,509 | 26,641 | 10,389,320 | 0.26% |
| macos | 906 | 0 | 906 | 3,103,961 | 0.03% |
| linux | 185,322 | 7,908 | 193,230 | 8,947,716 | 2.16% |
大量异常来自委内瑞拉的同一个 ASN,OONI 联系当地伙伴之后,确认是那批设备的时区设错了。排除委内瑞拉之后,Linux 的异常数字大幅下降,其他平台几乎不变。设置错误就足以产生误导性的记录,不一定出于恶意。
操作系统与版本信息的矛盾
OONI 检查软件名称与平台是否相符,例如 software_name = ooniprobe-android 却标成 iOS。这类 Android 软件出现在非 Android 平台的测量共有 718 条,一部分追查到 OONI 团队成员自己的开发机器,另一部分又是前面那个送中国数据的 ooniprobe-react-os。原文也列出几个陌生的软件名称(Vladhog、murakami-ooniprobe、MySorgenia、Dismantle 等),逐一查证来源。许多看起来可疑的数据,多半来自开发过程或第三方 fork,与攻击无关。
对数据使用者的意义
OONI 目前没有在数据里找到大量恶意污染,绝大多数异常来自 VPN、设置错误、开发机器或非官方分支。防御机制仍然要做,但目前的威胁不是迫在眉睫的大规模攻击。
anoni.net 的 OONI 观测覆盖率分析建立在同一份公开数据上,源头没有被大量污染,分析的基础就比较稳。四类发现也提醒我们,probe_cc 不等于当地实际的连接状况(ground truth)。VPN 造成的地理错配、时区设错这类噪声本来就存在,做分析时要先滤掉。
新的启发式构想
在既有规则之外,OONI 想再加上几种更高级的检测。定位一直是最大的难题,因为 GeoIP 数据库由探针自己查询,又会过期。考虑中的补强包括向手机操作系统取得移动网络的国家代码与运营商代码(MCC/MNC)、询问操作系统的定位服务,或改在服务器端做 IP 与地点的对照。每种做法原文都附了限制,例如服务器端的对照会被翻墙工具挡在中间、看不到真实 IP,询问定位权限则可能引起用户疑虑。另外也想加上网络层与协议层的异常检测,例如从 TLS 握手的指纹认出中间人设备(像是改写流量的杀毒软件)。
错误测量的处置原则
检测之后是处置,OONI 定了两条原则。第一,一条测量最终是否判定为错误数据,要经过人工审查,避免自动化规则误删正确的数据。第二,除非牵涉用户隐私,否则绝不回头修改已经送进来的数据。因为要经过人工把关,处置只能在错误数据进入数据管线之后进行。
可用的手段包括封锁行为异常的假名(pseudonym)、对投稿限流、动态调整某地区某时段可接受的投稿量,或轮换签发密钥。假名是匿名凭证系统给一台探针的标识,在同一个网络内固定不变,跨网络无法关联,也对应不到任何人的真实身份(原理见下一节)。原文也点出其中的两难,例如规定只有存在半年以上的探针才能投稿,可以挡下 sybil 攻击(用大量假身份送入数据),也会连带挡掉正常的新探针。
匿名凭证系统的运作方式
固定 ID 做法的问题
直觉的做法是给每个探针一个 ID,再由服务器端维护白名单。就算 ID 是随机生成的,只要固定不变就足以识别出单一探针,对隐私是灾难,而且探针换一个新 ID 就能绕过封锁。匿名凭证系统要解决的核心矛盾,是在不长期保存个人数据的前提下,同时做到访问控制与信任评分。
区间揭露的凭证
凭证的概念接近酒吧门口的年龄查验,店员看到一张证明已成年的证件就放行,不需要知道持有人的姓名、住址与生日。OONI 的凭证证明的是探针的资历够久、投稿数量够多。
凭证由服务器签发,只存在探针本地,服务器不保存,也不会再外传。凭证用密码学把探针的资历(age)与投稿数(msm_count)编码进去,而且只证明数值落在某个区间,例如投稿超过 1000 条、存在超过一周,不透露精确值。用区间取代精确数字是刻意的设计,精确的投稿数几乎是独一无二的指纹,会让探针被认出来,粗略的区间才不会泄露身份。
投稿时的零知识证明
投稿时,探针用凭证生成一段零知识证明(只证明某件事为真、不透露细节的密码学方法)。服务器只看到证明本身,看不到底下的真实数值,就能判断该条测量是否符合访问规则,例如某个国家、某个 ASN 的探针要投稿满 1000 条才收。信任分数还会锁定在特定的国家代码与 ASN 组合,一台探针在某个网络累积的信誉无法带到另一个网络使用,用意是防止有人先在门槛低的网络累积凭证,再拿去攻击别的网络。
一台全新的探针一开始资历浅、投稿数低,许多严格的规则都还达不到,只能先持续运行测量。每投一条,服务器验证通过之后返回一张更新过的凭证,把投稿数加一。时间与量累积够了,这台探针跨过满一周、满 1000 条的门槛,之后送出的测量就能标成 verified。整个过程中,OONI 始终没有取得它的固定 ID,也没有存下任何个人数据。
复制凭证与 sybil 攻击
凭证只存在探针本地,复制一百份能否假装成一百台各有信誉的探针?关键在前面提到的网络内固定。在同一个网络里,同一份凭证推导出来的假名都相同,复制再多份,仍然被视为同一台探针,不会变成一百个各自独立的可信身份。OONI 也坦白承认,光靠凭证无法完全解决 sybil 攻击,完整的防御要靠应用层的手段,例如限制新账号的注册速率、对每个区域的投稿量设上限。凭证的作用是提高攻击成本,对手需要先培养一批资历够久、送过够多测量的探针。
三种验证状态与长期指标
每条测量最后标成 verified、unverified 或 failed 三种状态,数据使用者可以自行决定要采信到什么程度。部分效果需要长期观察,OONI 会持续追踪三类测量的比例变化,用来诊断某次客户端更新是否让协议实现出错,或有旧版探针没有更新。他们也会统计各协议版本的探针数量,以及服务器端验证一条测量的耗时,及早发现性能退化。
隐私设计的参考价值
如何在不保存个人数据的前提下做访问控制与信任评分,是很多系统都会遇到的难题。OONI 用区间揭露、凭证只存本地,并放弃精准封锁单一探针来换取匿名性,这套取舍对关心隐私设计的人是很好的教材,也呼应社区个人隐私指引研究专题的主题。
数据可信度的结论
OONI 的公开数据目前没有被大量恶意污染,看到的异常多半来自 VPN、时区设错、开发机器这类无心之过,可以继续用来了解各地的封锁状况。想深入了解匿名凭证背后的密码学,OONI 另有两篇相关文章,一篇整理这套系统的设计需求2,一篇宣布系统的设计与实现3,后者的简体中文翻译见OONI Probe 匿名凭证系统的设计与实现。
原文十个大节对照
| 原文大节 | 重点 | 关键数字或结论 |
|---|---|---|
| Existing metrics and heuristics、Approach | 用既有数据建立检测基准 | 四个不牺牲隐私的检查角度 |
| IP geolocation mismatches | 探针回报位置对照真实 IP | 7.41% 对不上,多数是 VPN |
| Measurement volume anomalies | 单一探针投稿速率暴增 | 中国 ooniprobe-react-os 每秒 3 条 |
| Timestamp inconsistencies | 测量时间戳前后不一致 | 0.82% 异常,委内瑞拉时区设错 |
| Probe OS, version metadata | 软件名称与平台互相矛盾 | 718 条,含团队开发机 |
| New heuristics | 更高级的检测构想 | MCC/MNC、服务器端 GeoIP、TLS 指纹 |
| Mitigation strategies | 找到错误数据之后的处置 | 人工把关、不回改、限流、防 sybil |
| Naive solution | 固定 ID 做法的问题 | 固定 ID 足以去匿名,换 ID 又能绕过 |
| Anonymous credentials solution | 凭证式信任评分 | 区间揭露、只存本地、没有固定 ID |
| Future validation | 长期验证指标 | 追踪 verified、unverified、failed 的比例 |
名词对照
| 名词 | 说明 |
|---|---|
| 启发式(heuristic) | 一组简单、成本低的判断规则,不追求完美,先把可疑的测量筛出来 |
| OONI Probe | OONI 的手机与桌面 App,依网站清单逐一连接,回报每个网站在当地能否访问 |
| probe(探针) | 运行测量的设备或程序 |
probe_cc |
探针回报的国家代码(country code) |
probe_asn |
探针回报的 ASN |
| ASN | 自治系统编号(Autonomous System Number),一段 IP 地址的管理单位,通常对应一家 ISP 或机构 |
msm_count |
该探针累积投稿的测量数(measurement count) |
| check-in 端点 | 探针开始测量前调用的 API,会回报自己的国家代码与 ASN |
web_connectivity |
网络连接测试,OONI 最常见的测试项目,检查某个网站在当地能否访问 |
| ground truth | 当地实际的连接状况,用来对照探针回报的数据 |
| sybil 攻击 | 用大量假身份送入数据、扭曲观测结果的攻击 |
| pseudonym(假名) | 匿名凭证下一台探针的标识,在同一个地区与 IP 内固定,跨网络无法关联,不是个人身份 ID |
| verified、unverified、failed | 匿名凭证系统给每条测量的三种信任标记 |