如何在 Firestore 规则中同时发生两个查询

Posted

技术标签:

【中文标题】如何在 Firestore 规则中同时发生两个查询【英文标题】:How to make two queries occur together in firestore rules 【发布时间】:2021-05-14 23:09:44 【问题描述】:

我在应用程序中有一个敏感字段“goldCoins”,“goldCoins”会在用户正确回答问题时递增,并且每个问题只能递增一次。字段“goldCoins”在集合“记分卡”中,而所有正确回答的问题都存储在文档'userid/quizcode/questionNumber'中。

现在在我需要检查“questionNumber”时更新“goldCoins”,这是两个查询,但这是一个安全漏洞,因为任何人都可以轻松绕过检查“questionNumber”并增加值。

这是我的记分卡结构:

这是文档问题编号:

这是完成“goldCoins”增量的代码:

public boolean onEnter(String answer, Boolean onTime) 

  if (answer.equals(getValue().getAnswer())) 

    userScorecard.update("score", FieldValue.increment(getValue().getDifficulty()));
    userMetaScorecard.collection(quizName).document(String.valueOf(getValue().getQuestionNumber())).get().addOnSuccessListener(documentSnapshot ->
      if (documentSnapshot.exists());
      else 
        userScorecard.update("goldCoins", FieldValue.increment(1));

        QuestionSolved qs = new QuestionSolved(onTime, FieldValue.serverTimestamp());
        userMetaScorecard.collection(quizName).document(String.valueOf(getValue().getQuestionNumber())).set(qs);
      
    );

您可以很容易地看到“goldCoins”的嵌套增量可以通过将其退出循环来绕过。

我能想到的唯一检查是检查“goldCoins”是否仅增加了 1 的值。规则是:

function shouldUpdateGold()
   return request.resource.data.goldCoins <= resource.data.goldCoins+1 ||
   !request.resource.data.keys().hasAny(['goldCoins'])
   

match /scorecard/userId
  allow get: if isSignedIn(); 
  allow list: if isSignedin() && request.query.limit<=3;
  allow create : if isSignedIn() && isUser(request.resource.id);
  allow update : if isSignedIn() && shouldUpdateGold()
  

现在我应该如何检查每个问题一次更新“金币”,也欢迎任何架构更改。

【问题讨论】:

【参考方案1】:

从客户端写入关键数据是个坏消息。我推荐两种解决方案之一,都涉及云功能:

    REST API - 移除对您的 RTDB 的写入权限,然后在 Cloud Functions/Run 上设置一个 REST API 来设置数据,从而防止用户任意更改数据库值。

    RTDB 触发器 - 创建订阅onUpdate() 的云函数,以便在正确回答问题时,该函数将更新用户的金币总数。应禁用对/scorecard/id/goldCoins 的客户端写入访问。

【讨论】:

我正在制定一个 spark 计划,所以无法编写函数,建议进行一些架构更改(如果有)。 没有任何规则组合可以用来阻止任何一半感兴趣的人将他们的黄金数量增加到一百万。 Blaze 计划包括 Spark 计划的免费套餐,这意味着您可能无论如何都不会花费任何费用。

以上是关于如何在 Firestore 规则中同时发生两个查询的主要内容,如果未能解决你的问题,请参考以下文章

Firestore - 在本地合并两个查询

Firestore:查询和安全 (Swift)

如何在streambuilder中查询firestore文档并更新listview

Firestore 安全规则:更新时 request.resource.data.<prop> 会发生啥?

如何组合两个 Redux Firebase Cloud Firestore 查询?

使用规则禁用 Firebase Cloud Firestore 中的查询集合