第 5 章 · 隐私边界

这个工具自己做什么、不做什么

一个用来看网络流量的工具,最容易失去信任的方式就是自己在后台悄悄发请求。 所以边界写在这里,并且每一条都能在代码里对上。


一、默认不动

启动服务器只是把界面端起来,一次网络探测都不发。 按下界面上的开关,或者手动跑 cem probe,才开始采样。 关掉开关之后进程里没有任何定时器在跑 —— 是停,不是"降低频率"。

对应实现:0。Sampler.start() 才建线程, stop() 直接 join 掉。

二、探测的目标只有清单里那些

清单在 0,就是界面上「出网域名清单」 那一页,可以逐条看。除此之外:

  • 查 IP 归属会访问 origin.asn.cymru.com(DNS)和 ipinfo.io(HTTP);
  • 解析对账会访问 cloudflare-dns.com / dns.google 的 DoH 接口。

这五个是全部的外部依赖。它们收到的信息是"有人在查这个 IP / 这个域名", 不含你的任何标识。查询结果会缓存到磁盘(--cache-dir), 所以同一个地址不会反复去问。

三、不发数据到遥测接入点

对遥测域名(Datadog / Sentry)只做 TLS 握手,不发任何 HTTP 请求。 理由有两条:往别人的接入点写东西是污染他们的数据; 一个监控工具自己变成上报源很荒谬。

对应实现:cem/net.py 的 tcp_probe(),它握手完立刻关闭连接。

四、不解密、不抓包、不看内容

连接信息来自 lsof,读的是进程打开的 socket —— 只有"连到哪", 没有"发了什么"。不需要 root,不装 BPF / pktap,不做中间人。

所以有些问题这个工具答不了,也不假装能答:包里写了什么内容、 上报了哪些字段。要那种答案得解密 TLS,而那是另一回事。

五、不列出无法归属到 Claude 的浏览器连接

浏览器进程同时连着几十个别的站点。列出来有两个问题:界面被噪声灌满, 以及把你在访问哪些网站写进了采样文件。这个工具没有理由知道那些。

所以浏览器那一路只保留能归属到 Claude 域名的连接, 其余只报数量、不报地址。CLI 和桌面端是 Claude 自己的进程, 它连什么都算相关,全部保留。

对应实现:cem/sockets.py 的 filter_noise()。

六、采样结果默认不落盘

内存里保留最近若干轮(默认 720 轮)供界面画趋势,进程退出即丢。

要长期记录得显式给路径:

python3 -m cem serve --persist ./data/samples.jsonl

这个文件里有真实出口 IP、代理端口、内网地址、进程名 —— 换句话说就是你的网络画像。所以:

  • 仓库的 .gitignore 里 data/、*.jsonl、runs/、snapshots/ 全部挡掉了;
  • 要分享排查结果时,请手动检查过再发出去。

七、界面只监听回环

默认绑 127.0.0.1:8787,没有任何认证,也不该加认证然后开到局域网 —— 这个接口读得到你所有 Claude 进程的连接表。

要远程看,用 SSH 端口转发:

ssh -L 8787:127.0.0.1:8787 你的机器

服务端不设任何 CORS 头,所以别的网页读不到这些接口。 静态文件只从仓库的 web/ 目录读,路径先规范化再做前缀校验。

八、界面自己会加载 Google Fonts

web/assets/fonts.css 从 fonts.googleapis.com 拉字体。 在一个主题是"出网流量"的页面上,这件事值得点明:这是一个到第三方的请求。

不想要就把 web/index.html 里那一行 fonts.css 删掉 —— 页面用系统字体栈照样能读,只是字重对齐会差一点。

九、不需要的权限一个都不要

  • 不要 root;
  • 不读 ~/.claude 下的任何配置、会话、凭据;
  • 不读浏览器的历史、cookie、profile;
  • 不写任何系统配置。

如果哪天这个工具要求上面任何一项,那就是它变质了。