把朋友圈交给一个透明的沙箱:一次安全架构设计

· 2026-10-30 20:30 · 25 阅读

原创 Jeffery1st 2026-10-30 20:30 美国

最近帮一个团队设计了“追忆似水年华”的安全架构。朋友圈是很私密的数据,交给第三方不放心,交给命令行又没人会用。我们的办法是一个透明的沙箱:放在用户自己的 Mac 上,看得见,用完就清,采集的数据不经过任何第三方服务器。这是它的设计细节和它的边界

最近帮一个团队设计了一个系统的安全架构。项目叫“追忆似水年华”,做的事情很简单:把一个人十多年的朋友圈,做成手机里的一本书。文字、照片、视频,朋友的点赞和评论,一条不少,从第一页翻起。

Vision Pro 上,这本书摊开在客厅里

做这件事,安全是第一个问题,也是最难的一个。

朋友圈存着一个人最私密的东西:去过哪里,和谁在一起,孩子长什么样,哪一年过得不好。要把这些数据读出来,保留所有的视频、朋友的点赞和评论的话,微信官方的数据导出功能是不够的。常见的做法有两种。一种是把账号授权给第三方服务,由服务器去读。数据要过别人的服务器,换了谁都不放心,也确实不该放心。另一种是交给用户一套命令行工具,自己在电脑上跑。安全性取决于用户自己,可普通用户根本玩不转,更别提那些最想把朋友圈留下来的长辈。

“似水年华”的办法是第三种:交给用户一个沙箱,而且是一个透明的沙箱。它叫“似水年华助手”,英文名 Fish Tank,鱼缸。整个采集过程在用户自己 Mac 上的沙箱里进行,采集到的数据直接存进用户自己的手机,不经过任何第三方服务器,包括我们自己的。用户不用敲一行命令,扫个码就行;沙箱里在做什么,在手机上一直看得见。

下面是这套设计落到工程上的样子。各位都是行家,欢迎挑错。

威胁模型

我们防的是这几方:

我们自己。开发者、网站、服务器,都不应该有能力看到任何人的朋友圈。不是承诺不看,是设计上看不到。

网站被攻破。攻击者拿到网站和它持有的密钥以后,不能伪造吊销名单,不能推送假的更新。

局域网里的第三台设备。它插不进电脑和手机之间,也冒充不了任何一方。

捡到手机的人、拿到书的文件的人。离开那一部手机,书就是密文。

拿到别人授权证书的人。证书离开它绑定的账号就用不了。

不在防御范围里的:用户自己的 Mac 已经被攻陷;客户端本身的行为。这两条放在最后的“边界”里说。

一、透明的沙箱

隔离。助手用 QEMU 加 macOS 的 HVF 硬件加速,起一台 Debian 13 虚拟机(4 vCPU,4 GiB),里面运行官方的 Linux 版客户端。虚拟机没有显示设备,SSH 和 VNC 都只监听 127.0.0.1。客户端不随安装包分发,第一次运行时从官方下载站经 HTTPS 下载。

一次性。公共模板里没有任何账号,每次复用前做 SHA-256 校验;登录过的磁盘永远不会写回模板。账号、登录状态和这一轮的数据,放在一个加密的临时工作区里,这一轮结束就清掉。

透明。客体里是 Xvfb 加 Openbox,画面由 `x11vnc -viewonly` 送出来。Mac 上的窗口只解码画面,没有键盘、鼠标、剪贴板的通路,画面裁到客户端的窗口。手机上也有同一个画面,采集的时候一直能看:它在翻谁的朋友圈,翻到哪一年,下载了什么。在别人在场的场合,可以给电脑上的画面拉一道“窗帘”,只留手机上能看。

最小权限。它只读用户本人的朋友圈,不碰聊天记录。解析、整理数据的工具,在 `unshare --net` 加 seccomp 的环境里跑,没有网络。助手本地不调用任何大模型。

用完怎么收场。借来的电脑,这一轮结束就退出登录、关虚拟机、清空工作区,不留副本。用户标为“这是我自己的电脑”的那一台,会留下加密的账号资料和对这部手机的信任,下次更新点一下就能登录;但每一轮结束,同样退出登录、关虚拟机、删掉这一轮的缓存。想全部清掉,在手机上点“让电脑退出并清理”。

电脑上正在读朋友圈

二、电脑到手机:局域网、SAS、证书钉扎

发现。手机用 Bonjour(DNS-SD,`_fishtank._tcp`)在局域网里找电脑,广播的 TXT 记录里只有一个随机 id,没有名字和账号。找不到时,手机只扫自己所在的 /24 网段的几个固定端口。没有云端中继,数据不出局域网。

配对。第一次连接时,两边各生成一把临时的 P-256 密钥做 ECDH,先承诺、后揭示(commit/reveal),再经 HKDF-SHA256 派生出一个 6 位数,也就是“配对数字”,并且和 TLS 证书的指纹绑在一起。两边显示同一个数字,用户在电脑上点确认才开始。这是标准的 SAS(短认证串)做法:中间人想插进来,就得让两边算出同一个数字,而承诺在先,让他没有反复试的机会。

传输。走 HTTPS,手机钉住电脑证书的 SHA-256 指纹,证书一变就中止。标为“自己的电脑”以后,电脑在钥匙串里保存一把 P-256 签名密钥和最多 32 条设备记录,下次就不用再比对数字。

边采边传。朋友圈一批一批传进手机。每一批用一把随机的 32 字节密钥加密,按 1 MiB 分块做 AES-GCM;这把密钥再用 ECDH、HKDF 和 AES-GCM 包给手机的设备公钥。手机签收一批,回一张回执,电脑才删掉这一批。

电脑上的配对数字和确认配对

三、书只为这一部手机加密

每部 iPhone 第一次配对时,在 Secure Enclave 里生成一把 P-256 密钥,私钥不能导出,不进备份,也不跟着手机迁移。Android 用 Keystore,有 StrongBox 就放 StrongBox,没有就放 TEE。

书的每一代内容有一把内容密钥 K。助手临时生成一把 P-256 密钥,和手机的公钥做 ECDH,经 HKDF-SHA256 得到包装密钥,用 AES-256-GCM 把 K 封起来;书的内容分块,每块用 K 做 AES-256-GCM。整包导入时,文件名也由 HMAC-SHA256 派生,从名字看不出内容。

代价是:手机丢了,书也打不开了。这是有意的选择,没有恢复口令,也没有后门。授权还在,到授权那个时间点为止的朋友圈,可以重新读一遍。想在自己的另一台设备上也有一本,就在两台设备之间直接传,同样只走局域网,同样不经过服务器。

四、授权:离线证书和冷钥匙

证书。授权是一行字,大约 520 字节,`TM1.<内容>.<签名>`,Ed25519 签名。App 和助手都内置公钥,离线验证。

绑定账号,却不写账号。证书里没有账号,只有 SHA-256(16 字节随机盐 ‖ 账号) 和那把盐。拿到证书的人看不出是谁的;助手用登录的账号算一遍,对得上才干活。网站签完证书,就把用户填的账号删掉,订单上只留一个打码的提示(比如 `wx***23`),方便客服核对。

十对密钥,分冷热。网站的 Worker 只持有一把热钥匙,用来签证书。吊销名单由一把冷钥匙签名,它从不上网站;助手自己的更新清单,也由冷钥匙签名,验过才替换。所以就算网站被攻破,攻击者能多签几张证书,但伪造不了吊销名单,也推送不了假的更新;热钥匙一旦吊销,用它签过的证书换一把新钥匙重新签发。吊销名单只有助手去取,手机从不去取。

五、手机上的 App 连什么

App 不上传书,书里的任何内容都不发出去。它对外的请求只有几种,都写在设置里:

那天的天气:按照片的拍摄地查,只发出大约 10 公里精度的位置和日期,可以关;中国区的版本没有这个功能。

照片的地名:由系统的地理编码服务把坐标换成地名。

推荐码:交给系统浏览器去网站上查,App 自己不发请求。

局域网里找不到电脑时,向网站发一个 GET,问远程助手现在有没有空位。

边界

说清楚我们做不到的,和我们做了取舍的:

沙箱的出网不设白名单。虚拟机走普通的 NAT,因为客户端要连它自己的服务器和图片、视频的 CDN。隔离靠的是“一次性”和“数据处理工具不联网”,不是出网过滤。

客户端安装包没有固定哈希。下载走 HTTPS,校验的是包名、版本和架构。这一点各位可能会有不同意见。

边采边传的文件,用明文的 SHA-256 命名,能看出两个文件是不是同一个,看不到内容。

网站知道你的邮箱、付款记录和那个打码的提示。付款在 Stripe 和 Paddle 的托管页面完成,卡号我们不经手。

账号的哈希加了盐,但已经知道你账号的人,可以验证一张证书是不是你的。

你的 Mac 本身要是已经被攻陷,沙箱保护不了它。

远程助手。对没有 Mac 的人,2.3.0 另外提供了远程助手:在远程服务器上登录客户端、读朋友圈,用完清理。那是另一种信任模型,用之前 App 会单独提示风险,本文只讲在自己 Mac 上的这一种。

最后

如果你家里有人发了十几年朋友圈,这本书也许值得送给他们,或者先给自己做一本。iPhone、iPad 在 App Store 搜“追忆似水年华”,Android的app直接去官网下载APK。App 本身免费;用官方导出的压缩包,在 App 里就能做一本只有自己文字和照片的书。要连视频、朋友的点赞和评论一起,需要在 Mac 上用助手读取,授权在网站上买:

https://momentsregained.com/buy

既然参与了,那就必须要点福利。本公众号的读者,买一次性授权时用优惠码WAZY50,五折:在购买页选支付宝或微信支付都行,在推荐码框里填 WAZY50。

更多内容可以去网站看,点“阅读原文”。

阅读原文

跳转微信打开

本文转载自微信公众号「网安志异」,查看原文。版权归原作者所有,如有侵权请联系删除。