如何验证 Comoji 从不把你的按键发送到任何地方
Comoji 为 Mac 上的每一个应用免费加入 Slack 风格的 :emoji: 自动补全。
Comoji 需要“辅助功能”和“输入监控”权限,这是 macOS 上侵入性最强的两项权限。我们说一切都在本地处理,你输入的任何内容都不会被上传。Reddit 上有人把显而易见的质疑说得很好:他们基本上相信我们,但仅凭我们一句话就交出这些权限,还是觉得有点怪。
这个质疑很合理,而答案不应该是“请更加相信我们”。这篇文章就是操作指南:下面的每条命令都是只读的,大约需要五分钟,让你能在自己的电脑上确认 Comoji 在网络上做了什么、没做什么。所有内容的参考版本(包括完整的主机列表)都在安全页面上。
你实际上在检查什么
键盘记录器总得对它捕获的内容做点什么:要么发送到某处,要么写到某处。这是一个小而具体、可以验证的说法,而 macOS 自带了验证它的工具:你可以列出一个进程打开的所有网络套接字,统计它发送的每一个字节,读出它发布时的二进制文件中内置的主机名,还可以彻底阻断它的网络访问,看看什么会坏掉。
这里没有任何内容是 Comoji 专属的。对任何请求这些权限的 Mac 应用(包括我们的)都可以使用完全相同的步骤。这正是重点所在。
开始之前
让 Comoji 保持运行,然后打开“终端”(Applications → Utilities → Terminal)。下面的每条命令都是只读检查:不会安装、更改或删除任何东西。如果你安装的是开发版本,进程名为 ComojiDev,请把所有出现 Comoji 的地方替换成它。
首先,确认它正在运行并获取它的进程 ID:
pgrep -x Comoji你应该会得到一个数字。如果什么都没有,说明 Comoji 没有运行(它是菜单栏应用,所以请检查菜单栏而不是程序坞)。
第 1 步:边打字边观察它的网络连接
lsof 会列出打开的文件,而在 Unix 系统上,网络套接字也是文件。限定为 Comoji 的进程 ID 后,它会显示该应用当前打开的所有连接:
lsof -nP -i -a -p "$(pgrep -x Comoji)"预期的结果是完全没有输出。空响应意味着该进程没有持有任何网络连接。现在去打字吧:打开“信息”,用几次 :fire、:tada 和 :liz 补全,写上一两段话,然后再运行一次这条命令。依然是空的。
理论上,单次快照可能会漏掉在两次检查之间打开又关闭的连接,所以改为持续观察。把下面的内容粘贴到一个空闲的“终端”窗口,在你正常使用 Mac 的同时让它一直运行:
while :; do
printf '%s ' "$(date +%T)"
lsof -nP -i -a -p "$(pgrep -x Comoji)" | tail -n +2 | awk '{print $9}' | paste -sd' ' -
echo
sleep 2
done无论你打多少字,每两秒都只会得到一个后面什么都没有的时间戳。按 Control-C 停止。
接着,在这个循环仍在运行时,做一件*本来就应该*联网的事:在“信息”中输入 /gif 并搜索点什么。这时你会看到 api.giphy.com 和一个 giphy.com CDN 主机出现在时间戳旁边。这种对比正是这项测试有用的地方。它证明如果真有连接,这个循环一定会显示出来,所以你打字时的那些空行,意思就是它们看起来的意思。
第 2 步:统计字节数
nettop 会按进程追踪累计流量,所以连抽样检查来不及捕捉的短暂连接也逃不过:
nettop -P -p "$(pgrep -x Comoji)"让它保持打开,打几分钟字,并且不要使用 /gif 和 /sticker 选择器。bytes_in 和 bytes_out 两列会一直保持为零。按 q 退出。
第 3 步:从你下载的应用中读出主机名
进程只能连接它知道的地方,而主机名必须存储在二进制文件里。strings 能从编译后的文件中提取可读文本,所以不需要任何源代码就能列出它们:
strings -a /Applications/Comoji.app/Contents/MacOS/Comoji \
| grep -Eo 'https?://[A-Za-z0-9._-]+' | sort -u
/usr/libexec/PlistBuddy -c 'Print :SUFeedURL' \
/Applications/Comoji.app/Contents/Info.plist返回的结果是 Google 的贴纸图片 CDN(fonts.gstatic.com)、Firebase Storage 中的更新源(storage.googleapis.com),以及少量 comoji.io 和其他项目的地址,这些地址只会在你点击应用中的链接时交给你的浏览器。
有两点需要坦白说明,好让本文与你实际看到的一致,而不是一个修饰过的版本。api.giphy.com 是在代码中由主机名拼装而成的,并没有以完整 URL 的形式存储,所以它不会出现在第一份列表中;请用 strings -a … | grep -Eo '[a-z0-9.-]*giphy\.com' 直接搜索它,这个模式只匹配主机名,所以不会打印出同样打包在应用中的 API 密钥。此外,内置的 Sparkle 更新框架在 Contents/Frameworks 中带有它自己的文档 URL(sparkle-project.org、andymatuschak.org),这些是第三方库中的字符串,而不是 Comoji 会联系的主机。
第 4 步:阻断它,看看什么会坏掉
这是最有说服力的测试,因为它不依赖于信任任何输出。安装一个出站防火墙:LuLu 免费且开源,Little Snitch 则是老牌的商业选择。把它设置为对每个出站连接都发出提醒,然后永久拒绝 Comoji 的一切连接。
表情自动补全会一如既往地正常工作,无限期地,因为它从一开始就不需要网络。唯一会停止工作的,是更新检查以及下载尚未缓存的贴纸或 GIF 图片。如果“本地处理”的说法是假的,它就会在这里土崩瓦解,而且一目了然。
第 5 步:确认这个应用确实是我们的
上面的所有测试针对的都是你磁盘上的这份副本。值得确认一下,这份副本正是经过 Apple 公证的那一份,而且之后没有被任何人修改过:
codesign -dv --verbose=4 /Applications/Comoji.app
spctl -a -vvv -t exec /Applications/Comoji.app
codesign -d --entitlements - /Applications/Comoji.appcodesign 会打印出应用签名所用的 Developer ID,spctl 应该返回 accepted 以及 source=Notarized Developer ID,而权限(entitlements)的输出则显示了这个应用被允许做的所有事情。
我们这边做了什么
你能亲自完成的验证比一句承诺更有价值,但承诺本身也应该在某处得到强制执行。应用的每一次构建都会运行两项检查:
- Comoji 可以联系的完整主机列表是源代码中的一份声明,以网络访问面的形式公开,并在应用的“偏好设置 → 隐私”中显示。如果应用能够访问列表中没有披露的主机,一项自动化测试就会让构建失败。
- 第二项测试会扫描真正处理按键的代码,也就是事件监听、令牌缓冲区、匹配器和插入器,只要其中出现任何网络 API 或远程 URL,构建就会失败。Comoji 中能看到你输入内容的那部分代码不包含任何网络功能,也无法悄悄获得。
同一个页面还记录了我们决定*不*做的事情以及原因,包括开源输入路径和委托付费的第三方审计,这样你可以权衡其中的理由,而不必去猜。
如果你运行了其中任何一项,发现有与我们公布的内容相矛盾的地方,请发邮件到 support@comoji.io。我们宁愿更正页面或应用,也不愿让这个说法悄悄地出错。
至于应用实际上如何使用这些权限,功能页面介绍了 Comoji 能在哪些应用和网站中使用,以及按应用和按网站的停用列表,让它在你不希望它运行的地方保持安静。
常见问题
如何判断一个 Mac 应用是否在把我的按键发送到某处?
在“终端”中运行 lsof -nP -i -a -p "$(pgrep -x AppName)",列出该应用当前打开的网络连接;运行 nettop -P -p "$(pgrep -x AppName)",查看累计收发的字节数。如果想要决定性的测试,安装 LuLu 或 Little Snitch 这样的出站防火墙,彻底阻断该应用,再检查它的功能是否仍然可用。
Comoji 会上传我输入的内容吗?
不会。Comoji 没有账户、没有遥测、没有分析,也没有崩溃报告工具。按键只会保存在一个短暂存在的内存缓冲区中,仅用于检测以冒号开头的快捷方式,从不写入磁盘,也从不传输。该应用只联系四个主机:更新源、Google 的贴纸图片 CDN,以及在你使用 /gif 选择器时的 GIPHY API 和 CDN。
为什么 Comoji 需要“辅助功能”和“输入监控”权限?
“输入监控”让它能注意到你输入了 :fire 这样的快捷方式。“辅助功能”让它能找到获得焦点的文本框和光标位置,使弹窗出现在正确的位置,并把表情输入回该文本框。两者都不会被用来读取你文本框中的内容,安全密码框则会被完全忽略。
Comoji 是开源的吗?
目前不是。comoji.io 上的安全页面记录了这一决定及其理由,公开了完整的网络访问面,并给出了逐步的命令,让你可以针对自己下载的、经过公证的二进制文件验证本地处理的说法。
免费下载 Comoji Mac 版
Slack 和 Discord 风格的 :emoji: 自动补全,在 Mac 上随处可用。免费。