← 返回博客
8 novembre 2026 · 1 min 阅读时间

ProjectSend:客户本不该看到的公开链接

GHSA-g9g5-qxp7-f7v2:在 ProjectSend 中,客户可以读取并撤销员工在该客户自己的文件上创建的公开链接。Webcracy 的 Liam Giannini 发现了什么,以及为什么应升级到 2.8.0。

网络安全ProjectSendPHPLaravel漏洞披露
漏洞示意图:员工创建公开链接,客户从文件编辑器中读取该链接,并可以分享或撤销它

很多事务所、代理机构和小企业都通过门户与客户交换文件:客户上传自己的文件,员工进行检查,有时再通过公开链接分享给第三方。谁能创建这个链接、谁能看到它,是一项明确的决定。在 ProjectSend 中,没有发布文件权限的客户本不应该能分发公开链接。然而,只要打开自己某个文件的编辑页面,客户就能完整读取员工在该文件上创建的链接,甚至还能删除它们。

这就是安全公告 GHSA-g9g5-qxp7-f7v2 所描述的缺陷。该公告于 2026 年 11 月 8 日发布,问题已在 ProjectSend 2.8.0 中修复。漏洞由我们报告:发现者是 Liam Giannini(GitHub 上的 Liam-G),白帽黑客,也是 Webcracy 的联合创始人。感谢 ProjectSend 的维护者,他们在我们报告后的下一个版本中就纳入了修复。

Webcracy 与网络安全

除了开发网站和应用,Webcracy 也从事网络安全工作:渗透测试、代码审查、配置分析,以及对我们自己和客户所用开源软件的研究。Liam 是一名白帽黑客:他用攻击者的方法寻找漏洞,但目的是让漏洞得到修补。他会私下向维护者报告,并且只在修复发布之后才公开。这与我们在 exarch 和 FreeScout 上遵循的负责任披露流程相同。

ProjectSend 中的公开链接是什么

ProjectSend 是从自有服务器向客户分享文件最受欢迎、使用最广泛的开源应用之一:它诞生于 2014 年,在 GitHub 上有超过 2,000 颗星,仅 LinuxServer.io 的 Docker 镜像下载量就超过 490 万次。它用 PHP 编写,基于 Laravel。对于如此普及的项目,一个漏洞从来不只是少数人的问题。每个文件可以有一个或多个公开链接,即 /s/{token} 形式的地址,任何持有它的人无需登录即可打开。令牌就像一把钥匙:谁有链接谁就能进入,没有其他校验。因此,创建公开链接是一项单独的权限 upload_public,管理员可以为每个角色授予或拒绝。

ProjectSend 早已有一条关于“谁能看到什么”的明确规则:在门户中,客户只能看到自己创建的公开链接。如果员工在客户上传的文件上创建了链接,例如为了发给外部顾问,这个链接不会出现在客户的文件列表中。代码明确执行了这条规则,甚至还有一个自动化测试专门验证它。

规则没有被执行的地方

问题出在两个对同一对象使用了较弱规则的地方。

第一个是文件编辑器。拥有 edit_files 权限的客户可以修改自己上传的文件。打开编辑页面时,服务器正确地检查了客户是否有权修改该文件,但随后却把与之关联的所有公开链接都发送给了浏览器,没有按创建者过滤。每个链接都附带包含令牌的完整地址、标识符以及撤销地址。只要查看页面数据,就能拿到员工创建的链接。

第二个是撤销。删除链接的请求同样只检查了对文件的修改权限,而没有检查链接是谁创建的。因此客户可以删除员工的链接,而收到该链接的人会突然失去访问权限。

两种情况下的错误是一样的,而且非常常见:把对某个资源的权限,与对其所有关联对象的权限混为一谈。能修改一个文件,并不意味着能管理别人在该文件上创建的每一个链接。

有多严重

无法访问他人的文件,也无法获得员工权限:问题只涉及客户自己上传的文件,而且前提是员工在这些文件上创建过公开链接。但在这个范围内,员工的两项决定被绕过了。一个被拒绝了发布权限的客户,仍然可以把一个有效的公开链接分发给任何人,无需登录即可打开文件。他还可以撤销员工给第三方的链接,中断由他人决定的分享。公告将该问题评为中等严重性,归入 CWE-862(缺少授权)和 CWE-200(敏感信息暴露)。我们在报告中估算的 CVSS 3.1 评分为 5.4。

受影响的版本为 2.5.0 至 2.7.1。

我们如何验证

问题是在阅读 ProjectSend 2.7.1 的代码、比较通向同一批链接的不同路径时发现的:门户列表、文件编辑器和撤销操作。列表按创建者过滤,另外两处则没有。

为了确认这一点,Liam 使用项目中已有的测试工具编写了四个自动化测试,在隔离的 Docker 容器中运行,并使用内存数据库和虚构账户。这些测试验证了:编辑器会暴露员工的链接,客户可以撤销该链接,门户列表则会正确地将其隐藏,而获取到的链接在未登录时同样有效。两个现有测试起到了对照作用:没有 upload_public 的客户不能创建公开链接,也不能撤销不属于自己的文件上的链接。该行为在主开发分支上也得到了确认。

2.8.0 中的修复

10 月 29 日发布的 2.8.0 版本说明用一句话概括了修复:客户的文件编辑器现在只显示和撤销该客户自己创建的公开链接。这与门户早已执行的规则相同,只是扩展到了之前缺失的两个地方。员工的权限保持不变。

同一版本还修复了其他几个授权问题:API 令牌可以做超出授权范围的事情,失去文件访问权限后预先打包的 zip 仍可下载,上传内容落入用户已无权使用的文件夹,等等。仅凭这些,就不应推迟升级。

如果你在使用 ProjectSend

如果你的安装版本在 2.5.0 到 2.7.1 之间,请升级到 2.8.0 或更高版本。升级前请先阅读版本说明中的“do these yourself”部分:部分 API 令牌需要重新创建才能保留原有功能,而使用 Markdown 的自定义邮件模板现在会以纯文本显示。

升级后,也建议检查员工在客户上传文件上创建的公开链接。如果某个链接已与外部人员分享,而客户本不应知道它,升级并不能让它事后重新变成秘密:解决办法是撤销它并创建一个新链接。如果某个员工链接无缘无故消失了,现在你也知道了一个可能的原因。

更广泛地说,客户门户里存放着合同、发票和身份证件。它值得定期更新,也值得定期审查角色:谁有 edit_files,谁有 upload_public,以及他们是否真的需要。

我们为什么研究开源软件

我们经常推荐像 ProjectSend 这样的自托管开源工具:数据留在自己的服务器上,没有按用户收取的费用,代码可以阅读。但总得有人真的去读,而且要带着一种眼光去读:寻找程序中两个部分对同一事物应用了不同规则的地方。这类问题在正常使用应用时不会显现,只有对照代码才会浮出水面。向维护者报告这些问题,是我们回馈这些项目的方式,也让我们确切知道自己为客户安装的是什么。

如果你在使用客户门户、管理软件或定制应用,想知道权限是否真的如其承诺那样工作,我们很乐意和你聊聊。我们的渗透测试工作正是从这里开始:阅读代码和配置,找出哪里缺少检查,并准确告诉你我们验证了什么、没有验证什么。

聊聊你的应用安全

有项目想法?

让我们讨论如何用定制化数字解决方案帮助您的企业。

联系我们