通过 Firebase 身份验证和存储设置文件上传限制,中间没有服务器?

Posted

技术标签:

【中文标题】通过 Firebase 身份验证和存储设置文件上传限制,中间没有服务器?【英文标题】:Setting limits on file uploads via Firebase auth and storage without server in the middle? 【发布时间】:2017-03-23 15:00:23 【问题描述】:

我正在学习有关 Firebase 身份验证和网络应用中的存储的知识。我的想法是要求用户通过 Firebase 登录,然后上传图片。

我可以看到这可以通过 Firebase 身份验证和存储来实现。但是,我想限制他们可以上传的文件数和文件大小。

是否可以在 Firebase 控制台(或其他地方)内控制上传?在查看了 javascript 示例之后,我了解了如何将文件放入其中,并且我可以想象编写代码来查询 Firebase 以获取用户的上传计数,然后在客户端进行限制,但当然,这是一种完全不安全的方法。

如果我将它作为单页应用程序托管在 GitHub 页面上,我想知道是否可以在不涉及服务器的情况下设置这些限制。或者,我是否需要通过服务器代理我的上传,以确保我绝不允许用户上传超出我预期的内容?

【问题讨论】:

我看到很多教程和答案都描述了完全不安全的方法,作者甚至断言它是安全的:( 【参考方案1】:

您可以限制用户可以通过Firebase Storage's security rules 上传的内容。

例如,这(来自链接的文档)是一种限制上传文件大小的方法:

service firebase.storage 
  match /b/<your-firebase-storage-bucket>/o 
    match /images/imageId 
      // Only allow uploads of any image file that's less than 5MB
      allow write: if request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    
  

但是这些规则目前没有办法限制用户可以上传的文件数量。

想到的一种方法是为此使用固定文件名。例如,如果您限制允许的文件名编号为 1..5,则用户只能存储五个文件:

match /public/userId/imageId 
  allow write: if imageId.matches("[1-5]\.txt");

【讨论】:

这个文件名破解是我见过的最好的。您可以改为使用 Cloud Functions 调整文件大小,以便在事后稍微捕获规则破坏者,但这更加复杂和脆弱。 使用云函数、firestore 和 auth 声明,可以做到。请参阅下面的答案。【参考方案2】:

如果您需要每个用户的存储验证,则该解决方案有点棘手,但可以做到。

Ps.:您需要使用 Cloud Functions 生成 Firebase 令牌,但服务器不会在中间进行上传...

https://medium.com/@felipepastoree/per-user-storage-limit-validation-with-firebase-19ab3341492d

【讨论】:

【参考方案3】:

一种解决方案可能是使用 Admin SDK 根据保存每天上传计数的 Firestore 文档更改存储规则。

假设您有一个 userUploads/uid 的 Firestore 集合/文档,其中包含字段 uploadedFiles: 0lastUploadedOn

现在,一旦用户将文件上传到 Firebase 存储(假设在限制范围内且没有错误),您就可以触发 Cloud Function,它将读取 userUploads/uid 文档并检查 lastUploadedOn 字段是否早于当前日期上传文件的日期,如果是,则将 uploadedFiles 设置为 1 并将 lastUploadedOn 更改为上传的日期时间。否则,增加uploadedFiles 计数并将lastUpdateOn 更改为当前日期时间。一旦 uploadedFiles 值变为 10(您的限制),您可以使用 Admin SDK 更改存储规则。请参阅示例here。然后,将 userUploads/uid 文档中的计数更改为 0。

但是,有一点需要注意。规则的更改可能需要一些时间,并且该规则不应正在处理合法的异步工作。来自Admin SDK:

Firebase 安全规则需要 几分钟才能完全部署。使用 Admin SDK 部署规则时,请确保避免竞争条件,在这种情况下,您的应用会立即依赖尚未完成部署的规则

我自己没有尝试过,但看起来它会起作用。再想一想,更改规则以允许写入可能会很复杂。如果用户在第二天上传(规则更改后),上传错误处理程序可以触发另一个云函数来检查它是否是合法请求,将规则更改为正常并在一段时间后再次尝试上传,但它会是非常糟糕的用户体验。另一方面,如果您使用调度程序云功能每天检查 userUploads/uid 文档并重置值,则成本可能会很高(每百万用户每月约 18 美元 @ 0.06 美元/10 万次读取),并且如果用户在不同的时区,对于大多数用户来说可能无关紧要,这取决于他们是否经常上传。此外,规则有限制

序列化时,规则必须小于 64 KiB 的 UTF-8 编码文本 一个项目最多可以拥有总共 2500 个已部署的规则集。达到此限制后,您必须在创建新规则集之前删除一些旧规则集。

因此,针对大型用户群的每个用户规则可以轻松达到此限制(除了其他规则)。

也许最佳解决方案可能是使用Auth Claims。如果用户具有特定的身份验证声明令牌(例如canUpload: false),则最初具有拒绝写入规则。然后在上传时触发的云功能中,当用户达到限制时附加此声明。这将是实时的,因为它会立即阻止用户,以防止 Admin SDK 规则部署延迟。

要删除身份验证声明:

    通过上传错误处理程序中的另一个云函数检查 lastUploadedOn 是否已更改,从而删除声明 通过在上传前调用的单独云函数检查用户是否有 auth 声明并且 lastUploadedOn 是更早的日期,然后删除声明 此外,在登录过程中,如果lastUploadedOn 早于今天,则可以检查并删除它,但它的效率低于 2,因为它会在用户甚至没有上传任何内容时在 firestore 上构成不必要和不必要的读取

在 2 中,如果客户端尝试跳过呼叫,并且拥有身份验证声明,则她/他将无法上传,因为安全规则已阻止。否则,如果没有 auth 声明,那么他/她将通过正常流程。

注意:更改身份验证声明需要推送到客户端。看到这个doc。

【讨论】:

以上是关于通过 Firebase 身份验证和存储设置文件上传限制,中间没有服务器?的主要内容,如果未能解决你的问题,请参考以下文章

从 firebase 下载文件并上传到 Stripe 进行身份验证

如何在不使用 Firebase 身份验证的情况下保护 Firebase 存储? (下一个)

添加 Firebase 存储用户上传限制

Firebase 令牌身份验证错误

Flutter Firebase 存储:请求没有身份验证令牌

将文件上传到 Firebase 云存储时出错:“rules_version = 1 不允许列出存储桶中的对象”