将Firebase apiKey暴露给公众是否安全?

far*_*mio 368 javascript firebase

火力web应用指南规定我应该把给定的apiKey在我的HTML初始化火力点:

// TODO: Replace with your project's customized code snippet
<script src="https://www.gstatic.com/firebasejs/3.0.2/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: '<your-api-key>',
    authDomain: '<your-auth-domain>',
    databaseURL: '<your-database-url>',
    storageBucket: '<your-storage-bucket>'
  };
  firebase.initializeApp(config);
</script>
Run Code Online (Sandbox Code Playgroud)

通过这样做,apiKey暴露给每个访客.这把钥匙的目的是什么,它真的是公开的吗?

Fra*_*len 361

apiKey基本上只是在Google服务器上识别您的Firebase项目.有人知道这不是安全风险.事实上,他们必须了解它,以便他们与您的Firebase项目进行互动.

从这个意义上讲,它与Firebase历来用于识别后端的数据库URL非常相似:https://<app-id>.firebaseio.com.请参阅此问题,说明为什么这不是安全风险:如何限制Firebase数据修改?,包括使用Firebase的服务器端安全规则,以确保只有授权用户才能访问后端服务.

  • @EmmanuelCampos答案是是和否.是,如果您允许或希望其他人访问数据库中的所有数据.不,如果你不想要它们.Firebase数据库包含您控制的规则和规则 (25认同)
  • 如果机器人在我的应用程序中创建无限用户会怎样 我怎么能要求验证码. (13认同)
  • @ m.rufca,您的数据应该可供经过身份验证的用户使用.这就是诀窍.默认情况下,在您的firebase设置中,只有localhost和您的项目域有权从它们执行身份验证.因此,没有其他人可以创建通常适用于您的firebase的应用程序. (7认同)
  • 那么这意味着其他人能够访问我的firebase数据库中的所有数据? (5认同)
  • 在我的上一个问题中找到了我的答案https://support.google.com/firebase/answer/6400741感谢您的帮助.此链接可能会在将来帮助某人. (4认同)
  • @Rexford 用户管理怎么样?他们不会只是创建一个新的应用程序然后他们会使用我的应用程序的身份验证并且他们将能够在我的用户表中注册他们的用户吗? (3认同)
  • @ArtemArkhipov 如果网站被克隆然后从本地主机运行怎么办?假设有人使用项目 ID 复制了 js 代码,在本地主机上启动了开发服务器并运行它 - 这是否也使他能够访问 firebase(因为本地主机被授权执行authenticateaction) (3认同)
  • @Tamango这很好,因为阻止用户使用我的firebase服务发布应用程序.但是如果他在localhost上运行怎么办?我问这个因为我想在github上我的应用程序代码. (2认同)
  • @m.rufca,我试图找到一些相关内容,并从一位 Firebase 开发人员那里找到了合乎逻辑的答案(发布于 2016 年 12 月 16 日):“禁用 localhost 是不可能的,但能够在本地运行代码不会让他们比从生产站点运行它具有更多的权限。用户只能访问自己的 /users/$uid 节点,而无法访问任何其他用户的数据。这里不存在安全问题。” 当然,您需要先配置 Firebase 安全规则,以允许用户仅读取/写入自己的数据库部分。 (2认同)
  • 这篇博文还提供了很好的解释:https://javebratt.com/hide-firebase-api/ (2认同)
  • @AlexeyShevelyov 我自己对 Firebase 还很陌生,但从我读到的内容来看,即使有人完美克隆您的应用程序并且能够连接到您的 Firebase,也不意味着他们有权访问您的 Firebase。正确保护的 Firebase 后端应该需要身份验证才能执行任何操作,并且用户凭据并不是应用本身固有的东西。 (2认同)

now*_*now 63

建立在prufrofro和弗兰克面包车Puffelen的答案在这里,我放在一起这种解决方案并不妨碍刮,但可以使它更难使用您的API密钥.

警告:要获取数据,即使使用此方法,也可以在Chrome中打开JS控制台并键入:

firebase.database().ref("/get/all/the/data").once("value", function (data) {
    console.log(data.val());
});
Run Code Online (Sandbox Code Playgroud)

只有数据库安全规则才能保护您的数据.

不过,我将生产API密钥的使用限制在我的域名中,如下所示:

  1. https://console.developers.google.com/apis
  2. 选择您的Firebase项目
  3. 证书
  4. 在API密钥下,选择您的浏览器密钥.它应该如下所示:" 浏览器密钥(由Google服务自动创建) "
  5. 在" 接受来自这些HTTP参照请求(网站) "中,增加您的应用程序的URL(为例:projectname.firebaseapp.com/*)

现在,该应用仅适用于此域名.所以我创建了另一个专用于localhost开发的API密钥.

  1. 单击创建凭据> API密钥

这个不受限制,所以一定要保密.

我使用Webpack构建我的生产应用程序.为了确保我没有错误地发布这个新的不受限制的API密钥,我把它放在我的内部localhost,就像你通常使用API​​密钥一样.然后,在我的/env.development文件中,我每次都将密钥替换/env.production为生成版本,如下所示:

REACT_APP_API_KEY=###dev-key###
Run Code Online (Sandbox Code Playgroud)

默认情况下,正如Emmanuel Campos所述,Firebase只有白名单/src/index.js和您的Firebase托管域名.

  • 这对你来说工作正常吗?正在考虑为 Android 应用程序做同样的事情。我想知道为什么 Firebase 在安全部分没有涵盖这一点。 (3认同)
  • 到目前为止我没有遇到任何问题,但也许没有任何攻击 (2认同)
  • 他们的指南中没有提到这一点,因为它不会保护您免受刮擦.所有这一切都确保了其他人无法创建一个使用您的firebase来读取(或写入)数据的Web应用程序,如果它在正常的良好浏览器中运行的话. (2认同)
  • @FrankvanPuffelen 据我了解,这并没有多大区别,但可能会让滥用配额变得更烦人,因为在行为良好的浏览器中,与 HTML/JS 一起提供的 API 密钥只能在预期的情况下工作域而不是本地主机或其他任何东西。但我同意,与 Firebase 已经提供的保护相比,额外的保护是微不足道的。我会将答案改写为不那么戏剧性的内容。 (2认同)

Teo*_*ahi 16

我不相信将安全/配置密钥暴露给客户端.我不会称之为安全,不是因为有人可以从第一天起窃取所有私人信息,因为有人可能会提出过多请求,并且会耗尽您的配额并让您欠Google很多钱.

你需要考虑许多概念,限制人们不要访问他们不应该访问的地方,DOS攻击等.

我更希望客户端首先打到你的网络服务器,在那里你把客户端和服务器之间或服务器和firebase之间的第一手防火墙,验证码,云端,自定义安全放在你身边.至少你可以在到达firebase之前先停止可疑活动.你会有更多的灵活性.

我只看到一个使用基于客户端的配置进行内部使用的好用法.例如,您有内部域,并且您非常确定外人无法访问,因此您可以设置浏览器 - > firebase类型等环境.

  • 但这是否与“公开”任何其他REST API相同?我的意思是使用REST API URL可供用户使用。他们可以使用URL发出他们想要的任何请求并耗尽您的配额。firebase的工作是使用api键配置,以识别您的后端部分,并且后端必须可供用户发出请求。 (5认同)
  • @mbochynski但你可以在某种程度上直接请求资源,这会导致你支付账单.在Firebase方面,没有那么多的控制机制来防止DDoS攻击等.我的建议是让你的客户端调用你的REST API,但REST API应私下拥有API密钥,甚至在你点击Firebase资源之前,验证它们如果他们是合法的请求.(通过Cloudflare等).或从缓存中检索结果.然后,只有在您需要时才会点击您的Firebase资源.这就是我要实施的https://firebase.google.com/docs/admin/setup (3认同)
  • 在浏览器中公开键是一个严重的坏主意。那些写所有这些指南/文章的人,他们在想什么?http Referrer的安全性?容易被欺骗 (3认同)
  • 你们没有好好思考这个问题。不要将 API Key 视为秘密;它不是私钥,它只是一个 ID,因此 Firebase API 知道谁正在访问哪个项目。如果您想要很大的灵活性并且需要控制服务器/客户端交互的每一步,那么您不应该使用 Firebase,而应该使用 GCP。 (3认同)

Jus*_*man 12

API 密钥的暴露并不构成安全风险,但任何人都可以将您的凭据放在他们的网站上。

开放 API 密钥会导致攻击,这些攻击会占用 Firebase 的大量资源,这肯定会花费您的辛苦钱。

您始终可以将 Firebase 项目密钥限制为域/IP。

https://console.cloud.google.com/apis/credentials/key

选择您的项目 ID 和密钥,并将其限制为您的 Android/iOs/web 应用程序。


Ber*_*rci 9

虽然最初的问题得到了解答(API 密钥可以公开 - 必须根据数据库规则设置数据保护),但我也在寻找一种解决方案来限制对数据库特定部分的访问。因此,在阅读了这篇文章以及一些关于可能性的个人研究后,我想出了一种稍微不同的方法来限制未经授权的用户的数据使用:

我也将我的用户保存在我的数据库中,在相同的 uid 下(并将配置文件数据保存在那里)。所以我只是像这样设置数据库规则:

".read": "auth != null && root.child('/userdata/'+auth.uid+'/userRole').exists()",
".write": "auth != null && root.child('/userdata/'+auth.uid+'/userRole').exists()"
Run Code Online (Sandbox Code Playgroud)

这样,只有以前保存的用户才能在数据库中添加新用户,因此没有帐户的任何人都无法对数据库进行操作。

此外,仅当用户具有特殊角色并且只能由管理员或该用户本身进行编辑时才可以添加新用户(如下所示):

"userdata": {
  "$userId": {
    ".write": "$userId === auth.uid || root.child('/userdata/'+auth.uid+'/userRole').val() === 'superadmin'",
   ...
Run Code Online (Sandbox Code Playgroud)


pho*_*dio 7

可以包含它们,并且仅在 Firebase ML 或使用 Firebase 身份验证时才需要特别小心

Firebase 的 API 密钥与典型的 API 密钥不同:与 API 密钥的通常使用方式不同,Firebase 服务的 API 密钥不用于控制对后端资源的访问;这只能通过 Firebase 安全规则来完成。通常,您需要严格保护 API 密钥(例如,通过使用保管库服务或将密钥设置为环境变量);但是,Firebase 服务的 API 密钥可以包含在代码或签入的配置文件中。

尽管 Firebase 服务的 API 密钥可以安全地包含在代码中,但在某些特定情况下,您应该对 API 密钥实施限制;例如,如果您使用 Firebase ML 或通过电子邮件/密码登录方法使用 Firebase 身份验证。稍后在本页了解有关这些案例的更多信息。

更多信息请查看 官方文档


bzk*_*bzk 6

当启用用户/密码注册时,API 密钥暴露会产生一个漏洞。有一个开放的 API 端点,它接受 API 密钥并允许任何人创建新的用户帐户。然后,他们可以使用这个新帐户登录受 Firebase 身份验证保护的应用程序,或使用 SDK 使用用户/密码进行身份验证并运行查询。

我已经向谷歌报告了这个问题,但他们说它按预期工作。

如果您不能禁用用户/密码帐户,您应该执行以下操作: 创建一个云功能以在创建时自动禁用新用户并创建一个新的数据库条目来管理他们的访问。

例如:MyUsers/{userId}/Access: 0

exports.addUser = functions.auth.user().onCreate(onAddUser);
exports.deleteUser = functions.auth.user().onDelete(onDeleteUser);
Run Code Online (Sandbox Code Playgroud)

更新您的规则,只允许访问权限大于 1 的用户读取。

如果侦听器功能没有足够快地禁用帐户,则读取规则将阻止它们读取任何数据。


Bhu*_*ngh 6

我相信一旦数据库规则写得准确,就足以保护您的数据。此外,还可以遵循一些准则来相应地构建数据库。比如在users下做一个UID节点,把所有的信息放在它下面。之后,您将需要实现一个简单的数据库规则,如下所示

  "rules": {
    "users": {
      "$uid": {
        ".read": "auth != null && auth.uid == $uid",
        ".write": "auth != null && auth.uid == $uid"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

其他用户将无法读取其他用户的数据,而且域策略将限制来自其他域的请求。人们可以在Firebase 安全规则上阅读更多相关信息