Pixelfed 泄露来自其他 Fediverse 实例的私有帖子
fiona fokus
Pixelfed 泄露来自其他 Fediverse 实例的私有帖子
2025年3月25日 在 Fediverse 上关注不同服务器上的某人时,远程服务器会决定您是否被允许这样做。 这使得诸如私有帐户之类的功能成为可能。 由于实现上的错误,Pixelfed 忽略了这一点,并允许任何人关注其他服务器上的私有帐户。 当来自 Pixelfed 实例的合法用户关注您锁定的 fediverse 帐户时,该 Pixelfed 实例上的任何人都能够阅读您的私有帖子。 您无需成为 Pixelfed 用户也会受到影响。 Pixelfed 管理员应尽快更新到 v1.12.5,但升级可能是一个主要的障碍。
故事时间
两周前,我和我的伴侣在远离家乡的地方度假。 在外面度过漫长的一天后,我们正在享受当之无愧的休息,这时我看到她正对着手机露出困惑的表情。 “有人收藏了一个他们不应该看到的 toot。这怎么可能?”她举起手机对着我说。 “什么?不可能。” 但果不其然,这个 toot 仅对关注者可见,而点赞的人并没有关注她的 Mastodon 帐户。 当我查看 pixelfed.social 上其他人的个人资料时,我注意到该实例仍然声称该帐户正在关注她。 我已经害怕接下来可能发生的事情。 我在 pixelfed.social 上创建了一个帐户,并点击关注了我伴侣的 Mastodon 帐户,然后……我可以看到她的所有私有帖子。 它并没有告诉我需要等待对方接受我的关注,而是已经显示我正在关注她。 “哦,不,又来了”,我说,想到接下来几个小时要阅读 PHP 代码并编写报告,就感到害怕。
ActivityPub
为了理解这是如何发生的,我们必须了解一些关于 ActivityPub 的知识,它是驱动 Fediverse 的协议。
在大多数 ActivityPub 实现中,用户可以决定是否要手动审核新的关注者。 在 Mastodon 中,这可以通过禁用“自动接受新关注者”来实现。 有时它被称为 Locked Account。 现在服务器将属性 as:manuallyApprovesFollowers 添加到个人资料中,所有其他服务器都知道在您的用户名旁边显示小锁 🔒 符号。
当您点击关注某人的个人资料时,您的服务器会向远程服务器发送一条消息,请求关注。 然后,远程服务器会根据目标用户的选择,接受请求、拒绝请求或忽略请求,直到永远。
重要的是要补充一点,双向握手 的发生与另一个人是否锁定其帐户无关。 始终由远程服务器决定是否会发生该关注行为。 擅长规范的人会这样表达:
在发件箱中收到此 [关注请求] 的副作用是,服务器只有在随后收到以该 Follow activity 作为其对象的 Accept activity 时才应将该对象添加到参与者的 following Collection 中。 (来自 ActivityPub - 6.5 Follow Activity)
漏洞
Pixelfed 的 ActivityPub 实现过去(现在仍然)是不完整的。 他们导出了 as:manuallyApprovesFollowers 属性,但他们没有为远程帐户导入这些属性。 因此,远程帐户总是显示为 Not Locked。 虽然这对于用户来说很烦人,但它本身并不是安全问题。
但是,还有另一个问题。 当 pixelfed 假设一个帐户未被锁定时,它会立即将关注尝试视为已完成。 对于另一端的服务器来说,它看起来像一个正常的关注请求。 它可能会被拒绝,而 pixelfed 仍然确信存在关注关系。
以下是负责的代码:
1[](https://fokus.cool/2025/03/25/<#n1>)if ($private == true) {
2[](https://fokus.cool/2025/03/25/<#n2>) $follow = FollowRequest::firstOrCreate([
3[](https://fokus.cool/2025/03/25/<#n3>) 'follower_id' => $user->profile_id,
4[](https://fokus.cool/2025/03/25/<#n4>) 'following_id' => $target->id,
5[](https://fokus.cool/2025/03/25/<#n5>) ]);
6[](https://fokus.cool/2025/03/25/<#n6>) if ($remote == true && config('federation.activitypub.remoteFollow') == true) {
7[](https://fokus.cool/2025/03/25/<#n7>) (new FollowerController)->sendFollow($user->profile, $target);
8[](https://fokus.cool/2025/03/25/<#n8>) }
9[](https://fokus.cool/2025/03/25/<#n9>)} else {
**10[](https://fokus.cool/2025/03/25/<#n10>)** $follower = Follower::firstOrCreate([
11[](https://fokus.cool/2025/03/25/<#n11>) 'profile_id' => $user->profile_id,
12[](https://fokus.cool/2025/03/25/<#n12>) 'following_id' => $target->id,
13[](https://fokus.cool/2025/03/25/<#n13>) ]);
14[](https://fokus.cool/2025/03/25/<#n14>)
15[](https://fokus.cool/2025/03/25/<#n15>) if ($remote == true && config('federation.activitypub.remoteFollow') == true) {
16[](https://fokus.cool/2025/03/25/<#n16>) (new FollowerController)->sendFollow($user->profile, $target);
17[](https://fokus.cool/2025/03/25/<#n17>) }
18[](https://fokus.cool/2025/03/25/<#n18>) FollowPipeline::dispatch($follower)->onQueue('high');
19[](https://fokus.cool/2025/03/25/<#n19>)}
app/Http/Controllers/Api/ApiV1Controller.php Lines 859-877 重要的是,您的 Mastodon 或 GoToSocial 实例不会仅仅因为它提出要求就将您的私有帖子交给任何随机服务器。 只有当您至少有一个来自 Pixelfed 服务器的合法接受的关注者时,问题才会变得明显。 现在该服务器被允许获取您的所有私有帖子。 当它知道这些帖子时,它必须决定向谁显示它们。 当您接受一个关注者时,您不仅将保守秘密的信任放在他们身上,而且也放在他们的管理员和他们运行的软件上。
为什么这是一个严重的问题?
您很有可能在其中一个大型 Pixelfed 实例(如 pixelfed.social)上有一个关注者。 想要查看您的私有帖子的攻击者可以在那里创建一个帐户,关注您,并立即查看您的帖子。 您会收到一个关注请求,但您是否接受它并不重要。 您不可能注意到您的帖子暴露给陌生人,并且您无能为力。1 由于 pixelfeds 用户集中在 少数几个非常大的实例 上,因此这个问题更加严重。
报告
注意到似乎以前没有人注意到这一点,我知道负责任和谨慎地处理这些知识非常重要。 为了遵循负责任的披露过程的最佳实践,我拼凑了一份详细的分析报告,并要求就披露时间表达成一致。 这是使用 GitHub 的 Advisory 功能私下分享的,并同时通过电子邮件发送到他们的联系地址。 我写道:
该攻击向量的公开会将数千名用户置于危险之中。 因此,必须极其小心地处理它。 从我所能判断的来看,这是一个具有严重实际影响的严重问题。 请不要在没有进一步协调的情况下发布 advisory 或修复程序。
反应
大约 30 小时后,我收到了来自 Dansup(pixelfed 的唯一维护者)的第一次回复。
嗨,感谢您的报告,我正在努力修复。
两天后,他将修复程序推送到公共存储库中。
通过这样做,他公开了漏洞。 凭借诸如“更新 ActivityPub 助手,改进私有帐户处理”之类的提交消息,如果一个人知道他们在寻找什么,这就是一个明显的暗示。
所以我联系了 Dan:
[…] 不幸的是,既然提交已推送到公共存储库中,那就于事无补了。 现在不可能宣布一个宽限期,让实例运营商为协调更新做好准备。 因此,可行的方法是发布一个版本,并宣布管理员应尽快更新他们的服务器。 上一个版本 v0.12.4 已经过去了将近半年,因此一个版本将包含很多更改,这可能会进一步延迟管理员更新他们的服务器。 是否可以首先(或并行)发布一个 v0.12.5,其中仅包含向后移植的安全补丁?
他的唯一反应是:
是的,我正在准备发布!
几天后,该版本发布了。 虽然版本增量(从 v0.12.4 到 v0.12.5)意味着一个小的更新,但这是一个巨大的飞跃。 我们总共有 超过 450 个提交,包括需要新版本的 PHP,这在某些发行版上需要进行主要的系统升级。 在发行说明 中,没有任何明显的方式表明此版本中修复了一个关键漏洞,同时他们在 Mastodon 帖子 中提到了一个重要的隐私修复。
披露
理想情况下,开源软件中的严重安全问题应按以下方式处理:
- 问题报告给维护人员
- 在私下开发修复程序
- 在指定的日期公开发布安全版本
- 管理员和软件包维护人员为更新做准备
- 发布修复程序
- 管理员立即修补他们的服务器
过去,像 Mastodon 这样的其他项目就是这样做的。2 这就是我打算和要求做的。 相反,我的要求被忽略了,而且沟通不畅。
结论
我对 Pixelfed 如何管理这个漏洞感到失望。 对于一个(据称)拥有超过 15 万月活跃用户 3 且资金充足 4 5 6 7 的项目,我期望能做得更好。 这不是 Pixelfed 第一次处理安全问题不当。 几个月前,发生了一起类似的情况,一个 bug 8 导致数百个实例容易受到攻击,这显然导致 S3 API 密钥被盗。9 在撰写本文时,还有一个三年前的 GitHub issue,报告 2FA 出现故障。 🤯
维护者有 对社区表现出敌对行为 的记录。 他的新项目 Loops 正在成为头条新闻,被称为“fediverse 对 TikTok 的回应”,尽管它(仍然?)是闭源的,不进行联邦化,并且具有可疑的服务条款。10
至关重要的是,fediverse 基于信任。 我认为应该讨论一下鲁莽行为对 fediverse 的整体环境的影响。 Pixelfed 是最流行的 ActivityPub 实现之一,这带来了一定的责任。 此外,我们必须努力寻找更好的方法来处理信任。 例如,通过提供更多功能来限制与谁共享什么,并将透明度融入用户界面。 我们需要工具来允许实例管理员停止与已知易受攻击的软件版本进行联邦。 既可以减轻风险,又可以迫使实例管理员升级。
时间线
时间以 UTC 为单位
- 2025-03-14:发现并分析了漏洞
- 2025-03-16 15:00:我创建了 GitHub 报告并向 hello@pixelfed.org 发送了一封电子邮件
- 2025-03-17 21:30:Dansup 的第一次反应
- 2025-03-19 08:30:Dansup 公开推送修复程序
- 2025-03-21 07:50:我要求 Dansup 发布一个向后移植的安全版本
- 2025-03-24 06:00:Dansup 发布 pixelfed v1.12.5
- 2025-03-25 17:00:发布这篇文章
脚注
- 即使阻止该用户也没有帮助,因为令人惊讶的是,Pixelfed 似乎没有实现 federated Blocking。 您可以删除所有 pixelfed 关注者,甚至解除其实例的联邦关系……这将阻止泄露 新的 帖子 - 但对于现有帖子来说,损害已经造成,它们仍然保留在其他服务器上。 ↩
- https://mastodon.social/@Mastodon/110644992947398414 ↩
- https://fedidb.org/software/pixelfed ↩
- https://www.kickstarter.com/projects/pixelfed/pixelfed-foundation-2024-real-ethical-social-networks ↩
- https://nlnet.nl/project/Pixelfed/ ↩
- https://opencollective.com/pixelfed ↩
- https://www.patreon.com/dansup ↩
- https://github.com/pixelfed/pixelfed/security/advisories/GHSA-gccq-h3xj-jgvf ↩
- 一位实例管理员告诉我他们发生过这种情况。 ↩
- https://bajsicki.com/blog/loops-video-terms/ ↩