gpt4 book ai didi

google-cloud-firestore - 如何在 Cloud Firestore 安全规则中实现写入速率限制?

转载 作者:行者123 更新时间:2023-12-04 02:54:44 31 4
gpt4 key购买 nike

我有一个使用 Firebase SDK 直接与 Cloud Firestore 对话的应用程序从应用程序中。我的代码确保仅以合理的间隔写入数据。但是恶意用户可能会从我的应用程序中获取配置数据,并使用它向我的数据库写入无休止的数据流。

如何确保用户只能每隔几秒钟写一次 say ,而不必编写任何服务器端代码。

最佳答案

对您的数据库的每次读取或写入操作都由 security rules 在 Google 服务器上验证。您为项目配置的。这些规则只能由项目的协作者设置,但适用于访问项目中数据库的所有客户端代码。这意味着您可以在这些安全规则中强制执行此条件,即使是恶意用户也无法绕过它们,因为他们无权访问您的项目。
假设我们有一个 users集合,并且其中的每个文档都有一个带有用户 UID 的 ID。这些安全规则确保用户只能编写自己的文档,并且每 5 秒不超过一次:

match /users/{document=**} {
allow create: if isMine() && hasTimestamp();
allow update: if isMine() && hasTimestamp() && isCalm();
function isMine() {
return request.resource.id == request.auth.uid;
}
function hasTimestamp() {
return request.resource.data.timestamp == request.time;
}
function isCalm() {
return request.time > resource.data.timestamp + duration.value(5, 's');
}
}
演练可能会有所帮助:
  • 第一行确定了其中规则的范围,因此这些规则适用于 /users 中的所有文档。收藏。
  • 如果文档是他们的( isMine() ),并且有时间戳( hasTimestamp() ),则用户可以创建该文档。
  • 用户可以更新文档,如果它是他们的,有时间戳,并且如果他们不经常写( isCalm() )。
    让我们依次看看所有三个函数......
  • isMine()函数检查文档 ID 是否与执行写入操作的用户相同。自 auth.uid由 Firebase 根据登录用户自动填充,恶意用户无法欺骗此值。
  • hasTimestamp()函数检查正在写入的文档( request.resource )是否具有时间戳字段,如果有,则该时间戳是否与当前服务器端时间相同。这意味着在代码中,您需要指定 FieldValue.serverTimestamp()为了使写入可以被接受。所以只能写当前服务器端时间戳,恶意用户不能传入不同的时间戳。
  • isCalm()函数确保用户不会写得太频繁。如果 timestamp 之间的差异,它允许写入现有文档 ( resource.data.timestamp ) 和当前正在写入的文档 ( request.resource.data.timestamp ) 中的值至少为 5 秒。

  • 根据道格的评论:

    It's important to note that the above implements a per-document write limit, and not a per-account limit. The user is still free to write other documents as fast as the system allows.


    如果您想对他们编写的所有文档设置每个用户的写入速率限制,请继续阅读。

    这是我如何测试这些规则的 jsbin: https://jsbin.com/kejobej/2/edit?js,console .使用此代码:
    firebase.auth().signInAnonymously().then(function(auth) {
    var doc = collection.doc(auth.user.uid);
    doc.set({
    timestamp: firebase.firestore.FieldValue.serverTimestamp()
    }).then(function() {
    console.log("Written at "+new Date());
    }).catch(function(error) {
    console.error(error.code);
    })
    })
    如果您反复单击“运行”按钮,则仅在距上一次写入至少 5 秒后才允许进行下一次写入。
    当我每秒单击一次“运行”按钮时,我得到:

    "Written at Thu Jun 06 2019 20:20:19 GMT-0700 (Pacific Daylight Time)"

    "permission-denied"

    "permission-denied"

    "permission-denied"

    "permission-denied"

    "Written at Thu Jun 06 2019 20:20:24 GMT-0700 (Pacific Daylight Time)"

    "permission-denied"

    "permission-denied"

    "permission-denied"

    "permission-denied"

    "Written at Thu Jun 06 2019 20:20:30 GMT-0700 (Pacific Daylight Time)"



    最后一个例子是 每用户写入速率限制 .假设您有一个社交媒体应用程序,用户可以在其中创建帖子,并且每个用户都有一个个人资料。所以我们有两个集合: postsusers .并且我们希望确保用户每 5 秒最多可以创建一次新帖子。
    这方面的规则与以前几乎相同,例如:用户可以更新自己的个人资料,如果他们在过去 5 秒内没有写过,则可以创建帖子。
    最大的不同是我们将时间戳存储在他们的用户配置文件 ( /users/$uid ) 中,即使他们正在创建新的帖子文档 ( /posts/$newid )。由于这两个写入需要同时发生,我们将使用 BatchedWrite这阵子:
    var root = firebase.firestore();
    var users = root.collection("users");
    var posts = root.collection("posts");

    firebase.auth().signInAnonymously().then(function(auth) {
    var batch = db.batch();
    var userDoc = users.doc(auth.user.uid);
    batch.set(userDoc, {
    timestamp: firebase.firestore.FieldValue.serverTimestamp()
    })
    batch.set(posts.doc(), {
    title: "Hello world"
    });
    batch.commit().then(function() {
    console.log("Written at "+new Date());
    }).catch(function(error) {
    console.error(error.code);
    })
    })
    所以批处理写了两件事:
  • 它将当前服务器端时间写入用户的配置文件。
  • 它创建一个带有标题字段的新帖子。

  • 对此的顶级安全规则(如前所述)与以前几乎相同:
    match /users/{user} {
    allow write: if isMine() && hasTimestamp();
    }
    match /posts/{post} {
    allow write: if isCalm();
    }
    因此,如果用户自己的配置文件文档,并且该文档包含等于当前服务器端/请求时间的时间戳,则用户可以写入配置文件文档。用户可以写一篇文章,如果他们最近还没有发布。 isMine()的实现和 hasTimstamp()和以前一样。但是执行 isCalm()现在在写入操作之前和之后查找用户配置文件以进行时间戳检查:
    function isCalm() {
    return getAfter(/databases/$(database)/documents/users/$(request.auth.uid)).data.timestamp
    > get(/databases/$(database)/documents/users/$(request.auth.uid)).data.timestamp + duration.value(5, 's');
    }
    get()的路径和 getAfter()不幸的是必须是绝对的和完全合格的,但归结为:
    // These won't work, but are easier to read.    
    function isCalm() {
    return getAfter(/users/$(request.auth.uid)).data.timestamp
    > get(/users/$(request.auth.uid)).data.timestamp + duration.value(5, 's');
    }
    需要注意的几点:
  • 就像之前我们比较两个时间戳一样。但在这里我们从不同的文档中读取时间戳。
  • 这需要阅读两个额外的文档,这意味着您需要为两次额外的阅读操作付费。如果速率限制的目的是不对恶意用户的写操作收费,这可能不是您要寻找的解决方案。
  • 关于google-cloud-firestore - 如何在 Cloud Firestore 安全规则中实现写入速率限制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56487578/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com