【问题标题】:Firebase security "read" rule work only in simulatorFirebase 安全“读取”规则仅在模拟器中有效
【发布时间】:2019-12-31 16:18:23
【问题描述】:

我正在使用 firebase 创建一个 android 应用程序。我的数据库结构是这样的,

user:{
     $uid:{
           uname: abc,
           age: 20,
           email: abc@gmail.com,
           premium: true,
           score: 80
           }
       }

安全规则是这样的,

  {
   "rules": {
           "user":{

                 "$uid":{
                        "score":{
                              ".read":"auth.uid===$uid",
                              ".write":"auth.uid===$uid"
                               },
                        "$others":{
                                ".read":"auth!=null",
                                ".write":"auth!=null"
                                }
                       }
                   }
             }
    }

这是我从 firebase 读取数据的代码,

DatabaseReference myRef = FirebaseDatabase.getInstance().getReference()
                               .child("user").child(uid);

    myRef.addListenerForSingleValueEvent(new ValueEventListener() {
          @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
           users = dataSnapshot.getValue(User.class);
            //set values to associated textviews
        }

         @Override
       public void onCancelled(DatabaseError databaseError) {}

  });

问题是“.read”规则仅在模拟器中,尽管“.write”规则在应用程序和模拟器中都有效。当我将规则更改为此时,

  {
   "rules": {
           "user":{
                 "$uid":{
                          ".read":"auth!=null",
                          ".write":"auth!=null",
                        "score":{
                              ".read":"auth.uid===$uid",
                              ".write":"auth.uid===$uid"
                               },
                        "$others":{
                                ".read":"auth!=null",
                                ".write":"auth!=null"
                                }
                       }
                   }
             }
    }

它可以读写。但这并不安全。为什么即使 auth.uid = myUid 也无法读取数据?但是“.write”规则总是很好。

【问题讨论】:

    标签: android firebase-realtime-database firebase-security


    【解决方案1】:

    在您的第一个解决方案中,没有人可以阅读 /users/$uid,因此您的听众被拒绝是有道理的。

    要使其正常工作,您需要授予可以读取所有数据的用户对/users/$uid 的访问权限。据我所知:

    1. 用户可以读取自己的整个节点。
    2. 所有经过身份验证的用户都可以读取除用户分数之外的所有内容。

    你能达到的最接近的是:

    {
        "rules": {
            "user": {
                "$uid": {
                    ".read": "auth.uid===$uid",
                    ".write": "auth.uid===$uid"
                    "score": {
                    },
                    "$others": {
                        ".read": "auth!=null",
                        ".write": "auth!=null"
                    }
                }
            }
        }
    }
    

    使用这些规则:

    1. 每个用户都可以读取他们的整个节点。
    2. 所有经过身份验证的用户都可以读取其他用户的每个特定属性,但不能读取他们的分数。

    因此每个身份验证用户可以读取/users/anyUid/foo/users/anyUid/bar,但不能读取/users/anyUid/score


    这里的棘手点是用户仍然无法读取任何用户的/users/anyUid。这样做的原因是权限级联:一旦你可以读取一个节点,你就可以读取该节点下的所有数据。因此,一旦您授予任何人对 /users/$uid 的读取权限,您就无法在较低级别删除该权限。

    因此,您通常希望将需要单独访问权限的数据存储到单独的顶级节点中。如果我们稍微改写你的规则,我们会:

    • 所有经过身份验证的用户都可以读取所有用户配置文件。
    • 经过身份验证的用户只能读/写自己的分数。

    这将转化为这个数据结构:

    profiles: {
      uid1: { ... },
      uid2: { ... }
    },
    scores: {
      uid1: ...,
      uid2: ...
    }
    

    现在您可以通过以下方式轻松保护它:

    {
        "rules": {
            "profiles": {
                "$uid": {
                    ".read": "auth!=null",
                    ".write": "auth!=null"
                }
            },
            "score": {
                "$uid": {
                    ".read": "auth.uid===$uid",
                    ".write": "auth.uid===$uid"
                }
            }
        }
    }
    

    【讨论】:

    • 第一种意见也不起作用,因为实际上还有另一个“高级”节点,它对于读写都是“假”的。第一种方式允许用户读取所有子节点。有什么方法可以尝试(每个子节点的规则)?如果没有办法,我会尝试第二种意见。
    猜你喜欢
    • 1970-01-01
    • 2019-02-05
    • 2022-01-21
    • 2018-03-17
    • 2020-07-11
    • 2015-03-25
    • 2021-09-21
    • 2020-11-03
    • 2016-11-05
    相关资源
    最近更新 更多