使用firebaseSimpleLogin的Firebase用户帐户安全性
我正在尝试为使用firebase的应用程序找到设计安全性的最佳方法
基本问题
我们希望用户的数据安全。 我们不希望恶意代理能够访问Firebase数据库上的其他用户的私有数据。 似乎应该通过firebaseSimpleLogin来解决这个问题,但是尽管仔细检查了文档,我们还没有看到。
问题细节
- 我们提供具有用户帐户的应用程序,这些用户拥有私人数据
- 用户应该只能阅读:
- 他们自己的数据
- 与所有用户相关的应用范围内的数据,例如所有用户在最初创建帐户时获得副本的模板,其原始副本位于fb db
- 另一个用户的一部分数据,如果其他用户明确决定与他们分享,例如他们制作的游戏他们希望其他用户拥有副本
- 现在,用户使用FirebaseSimpleLogin登录。 这是有问题的,因为任何恶意用户都可以合法地创建自己的帐户,并使用他们的帐户的电子邮件和密码登录恶意脚本,并访问数据库
我们考虑过的解决方案
1.存储user_secret以确保用户具有合法访问权限
- 灵感来自第二种方法,以回答如何设置Firebase安全规则以仅接受来自iOS应用程序的连接
- 结构看起来像security-> user_secret-> associated_user OR security-> user – > {all_valid_user_secrets}
- 安全规则:“。read”:“root.child(’user_secrets /’+ auth.uid).exists()”
- 我们可以为每个用户存储多个用户密钥,允许从多个经过validation的来源(iOS应用,网络应用等)进行访问
#1的问题
- 我们如何限制对安全子进程的写/读访问?
- 服务器不存在SimpleLogin
- 我们不希望这些信息可见,因为恶意用户可以在技术上阅读它以查找有关他/她自己帐户的信息,然后使用它来仔细阅读其余的数据库
- 与问题陈述中的问题相同:用户可以合法地生成帐户,然后使用这些凭据获得对db的恶意访问
2.暂时存储用户密码
- 用户启动登录
- 节点服务器生成密码,将其存储在Firebase中的受限安全子级中(服务器可以执行此操作,因为Firebase机密允许完全访问)
- 我们一直使用Firebase SimpleLogin授权firebase客户端
- 用户与应用程序进行交互。 如果存在由节点服务器写入的安全子级,则Firebase安全规则仅允许读/写访问
- 用户启动注销/崩溃/关闭应用程序
- 节点服务器从受限安全子节点删除密码
- 像我们一样取消对Firebase ref的授权
- 完成
问题#2 – 此方法的问题是用户在登录时容易受到攻击,因为他们的安全信息会存在。
3.使用内置的Firebase安全规则
- 我们希望有一个内置的firebase解决方案,但还没有找到解决上述问题的解决方案。 如果你能指出一个非常棒的话。
我们希望有人可以帮助阐明这里的最佳方法,无论是使用我们的想法还是其他途径。 非常感谢你的帮助。
您基本上要求某人为您的应用编写完整的安全架构。 如果您在尝试将安全规则应用于这样的复杂结构之前彻底理解安全规则,那会更好。 从头到尾对文档进行的一项很好的研究将为您提供一个完整function解决方案。
让我们只关注似乎是核心问题,即您不确定如何使用仅客户端解决方案使邀请安全地工作。 (由于能够创建我们自己的令牌所提供的额外火力,node.js解决方案也应该明白这种理解)我会在这里做出很多假设; 只需将这些想法应用于您当前的用例即可。
数据结构:
/invites/$game_id/$uuid/true (a place to store invited users) /accepted_invites/$gameid/$userid/$uuid/true (a place to store accepted invites) /games/$game_id (the place we want to invite users into) /users/$user_id (a place where we put profiles for existing users)
1)当新用户在应用中创建帐户时,将其个人资料写入/ users。 安全用户/如下:
"users": { "$userid": { ".write": "auth.uid === $userid" } }
2)要邀请用户,请创建一个uuid ,表示一个不可授权的ID,并将其存储在invites / $ game_id中。 请注意,没有人应该能够阅读此路径。
"invites": { "$game_id": { "$invite_id": { // I can only create an invite for groups I'm a member of ".write": "root.child('games/'+$game_id+'/members/'+auth.uid).exists()", ".validate": "newData.val() === true" } } }
3)要加入游戏,用户必须首先接受访问令牌,这certificate他们知道令牌(因为他们无法读取邀请路径)并将令牌链接到他们的帐户ID。 此条目的值是邀请的uuid。
"accepted_invites": { "$game_id": { "$user_id": { ".write": "auth.uid === $user_id", ".validate": "root.child('invites/'+$game_id+'/'+newData.val()).exists()" } } }
4)如果用户已经接受邀请或者最初创建并且还没有成员,则用户可以将自己写入游戏( !data.parent().exists()
规则)
"game": { "$gid": { "members": { "$uid": { ".write": "auth.uid === $uid", // I can join a group if a) I'm creating it or b) I have accepted an invite ".validate": "!data.parent().exists() || root.child('accepted_invites/'+$gid+'/'+auth.uid).exists()" } } } }
客户端解决方案的另一个增强function是为邀请分配一个优先级,表示它们何时到期,然后在安全规则中引用该优先级来控制令牌有效的时间。
在@Kato的建议的帮助下,我最终得到了#3的想法。 到目前为止,使用内置规则和设计模式的解决方案使我们能够避免需要第三方auth服务器。 架构的一些示例如下:
"game_detail" : { "$game_detail" : { ".read" : "data.child('owner').val() === auth.email || root.child('admins').val() === auth.email", ".write" : "newData.child('owner').val() === auth.email || root.child('admins').val() === auth.email" } },
然后,使#3成为可能的附加密钥是,除了具有安全规则模式之外,我们还创建了一个通用管理员凭证,匿名用户在登录时可以使用它来访问数据库的子集,执行必要的跨账户操作。
感谢大家的投入。