How to make data unreadable once the time indicated on its time stamp has passed?

后端 未结 1 1088
囚心锁ツ
囚心锁ツ 2021-01-15 01:49

Let’s say for instance a user writes about an event to the Firebase database, what the user writes has a time stamp attached to it and other users are able to read what was

1条回答
  •  囚心锁ツ
    2021-01-15 02:33

    There's a big difference here between whether you have a single item, or a list of items.

    Securing access to a single node

    If you have a single node like this in your database:

    "content": {
      "expiresAt": 1565275079920,
      "content": "This content is only readable until Thu Aug 08 2019 07:37:59 GMT-0700"
    }
    

    You can ensure this node is only readable until its expiry timestamp with these rules:

    {
      "rules": {
        "content": {
          ".read": "data.child('expiresAt').val() < now"
        }
      }
    }
    

    When somebody attaches a listener to /content up until the expiry timestamp it will be allowed, after that any new listeners will be rejected.


    Securing access to a list of nodes

    But things get more complicated when you have a list of data as:

    1. You can only read/query data if you have read access to all that data.
    2. Once you have read access to a node, you have read access to all data under that node.

    Combined these two fact mean that security rules cannot be used to filter data.

    So if you have a list of these nodes above:

    "content": {
      "-Ldshdh13...": {
        "expiresAt": 1565275079920,
        "content": "This content is only readable until Thu Aug 08 2019 07:37:59 GMT-0700"
      },
      "-Ldshdh13...": {
        "expiresAt": 1565277079920,
        "content": "This content is only readable until Thu Aug 08 2019 08:11:19 GMT-0700"
      },
      ...
    }
    

    In order to be able to query this data, the user must have read permission on /content. And as soon as they have full read permission on /content, you can't keep them from reading certain nodes under there.

    The only way to make this scenario work is to use a combination of a query and a security rule that validates this query.

    Step 1: query for only the data that you're allowed to read

    So if you should only be able to read data that expires in the future:

    var ref = firebase.database().ref('content');
    ref.orderByChild('expiresAt').startAt(Date.now()).once('value',...
    

    Step 2: use security rules to only allow reads with this query

    The security rules will now check whether the user is passing the correct orderBy and value in to their query so that they're only accessing non-expired data:

    {
      "rules": {
        "content": {
          ".read": "query.orderByChild == 'expiresAt' &&
                    query.startAt >= now"
        }
      }
    }
    

    A few things still to note:

    • The security are applied when the listener is attached. So the value of now is only checked at that moment, it doesn't get modified in any way after that. This is usually not a security problem, but means you will need to remove outdated data in the application code too after attaching the listener.
    • You may need to tweak the rule a bit, as the Date.now() in the client and the now in the rules may not be exactly the same. Adding a few seconds in the security rule may be a good idea.

    For further reading, I highly recommend:

    • documentation on the fact that permissions cascade
    • documentation on rules-are-not-filters
    • previous questions on rules are not filters. Note that many of these probably predate the introduction of query-based security rules.
    • documentation on query based security rules

    0 讨论(0)
提交回复
热议问题