向公众公开Firebase apiKey是否安全?


436

火力地堡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>

这样一apiKey来,每个访问者都可以接触到。该密钥的目的是什么,真的意味着要公开吗?


1
我认为,只要您设置Firebase AuthFirebase数据库规则,就可以公开提供该信息。
abbaf33f

用户Christophe Quintard已添加了一个非常有用的文章的链接,其中包含有关Firebase API安全性的其他信息,因此我将其重新发布在这里:javebratt.com/hide-firebase-api(该评论将消失,因为它已附加到另一个用户的由于质量差而被标记为删除的答案)
Oliver Schafeld

我只想指出一点,因为这个特定的框架恰好可以公开它的API,但这并不意味着其他框架都可以。不想让任何人以一般“公开API密钥是可以的”的想法离开本文。
YungGun

您可以毫无问题地公开密钥。为了安全起见,您可以将其限制在生产中的特定域中,以便其他任何人都不能从任何随机域名进行调用API调用。为了使其更加安全,从生产应用程序中删除localhost。
BLΛCK

1
我认为从引荐来源者白名单中删除localhost不会做任何事情,除了使测试更加困难之外。这种配置不像IP白名单;认为它更像是CORS配置。Firebase的工作方式是直接从客户端调用这些API路由,而不对其进行代理。这就是为什么您的网页需要API密钥。如果一个不好的角色想从Postman调用您的API路由,则您的引荐来源者白名单不会阻止它们。它仅用于防止其他公共站点阻塞您的服务器。
forresthopkinsa

Answers:


450

此配置代码段中的apiKey只能标识您在Google服务器上的Firebase项目。知道它不是安全风险。实际上,他们有必要知道它,以便他们与Firebase项目进行交互。相同的配置数据也包含在每个使用Firebase作为后端的iOS和Android应用程序中。

从这个意义上讲,它与数据库URL非常相似,后者在同一代码段中标识了与您的项目关联的后端数据库https://<app-id>.firebaseio.com。有关为何这不构成安全风险的问题,请参见以下问题:如何限制Firebase数据修改?,包括使用Firebase的服务器端安全规则,以确保只有授权用户才能访问后端服务。

如果您想了解如何确保所有对Firebase后端服务的数据访问均得到授权,请阅读有关Firebase安全规则的文档。


如果您想降低将此配置数据提交到版本控制的风险,请考虑使用Firebase HostingSDK自动配置。尽管密钥仍将以相同的格式出现在浏览器中,但是它们不再被硬编码到您的代码中。


7
因此,这意味着其他人将能够访问我的Firebase数据库中的所有数据?
伊曼纽尔·坎波斯

31
@EmmanuelCampos答案是“是”和“否”。是,如果您允许或希望其他人访问数据库中的所有数据。不,如果您不希望他们这样做。Firebase数据库具有规则,您可以控制规则
KhoPhi

5
在这里找到我的最后一个问题的答案support.google.com/firebase/answer/6400741感谢您的帮助。此链接将来可能会对某人有所帮助。
伊曼纽尔·坎波斯

7
@ m.rufca,您的数据应可供经过身份验证的用户使用。这就是窍门。默认情况下,在您的Firebase设置中,仅本地主机和项目域被授权从它们执行身份验证。因此,没有其他人可以创建通常可以与您的Firebase一起使用的应用程序。
Artem Arkhipov

15
如果漫游器在我的应用上创建了无限的用户,该怎么办。我如何要求验证码。
穆罕默德·乌默尔

79

这里基于prufrofro和Frank van Puffelen的答案的基础上,我整理了此设置,该设置不会阻止抓取,但会使使用API​​密钥的难度稍大一些。

警告:即使使用这种方法也要获取数据,例如,可以简单地在Chrome中打开JS控制台并输入:

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

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

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

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

现在,该应用将仅适用于该特定域名。因此,我创建了另一个API密钥,该密钥对于本地主机开发是私有的。

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

默认情况下,如Emmanuel Campos所述,Firebase仅将白名单localhost和Firebase托管域列入白名单


为了确保我不会错误地发布错误的API密钥,我使用以下方法之一自动在生产中使用受限制的方法。

建立反应应用程式的设定

/env.development

REACT_APP_API_KEY=###dev-key###

/env.production

REACT_APP_API_KEY=###public-key###

/src/index.js

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  // ... 
};

我之前对Webpack的设置:

我使用Webpack来构建生产应用程序,并且像平常一样将我的dev API密钥放入我的产品中index.html。然后,在我的webpack.production.config.js文件中,每次index.html复制到生产版本时,我都会替换密钥:

plugins: [
    new CopyWebpackPlugin([
      {
        transform: function(content, path) {
          return content.toString().replace("###dev-key###", "###public-key###");
        },
        from: './index.html'
      }
    ])
  ]

1
这样对您来说还好吗?正在考虑对Android应用程序执行相同的操作。我想知道为什么Firebase在安全性部分没有涵盖这一点。
steliosf

2
到目前为止,我还没有遇到任何问题,但也可能没有受到攻击
现在

3
他们的指南中未提及此内容,因为它不会保护您免遭刮擦。所有这些确保了其他人无法制作使用Firebase读取(或写入)数据的Web应用程序(如果该应用程序运行在正常行为良好的浏览器中)。
thoutbeckers

@thoutbeckers你说得对,谢谢。我编辑了答案,但留下了可能仍然有用的方法。
现在

1
@FrankvanPuffelen据我所知,这并没有太大的区别,但是可以使您的配额滥用稍微麻烦一些,因为在行为良好的浏览器中,HTML / JS附带的API密钥仅适用于预期的域,而不是localhost或其他任何域。但是我同意,与Firebase已经提供的保护相比,增加的保护是微不足道的。我会改写不太戏剧性的答案。
现在

22

我不相信将安全性/配置密钥公开给客户端。我不会将其称为安全的原因,不是因为有人可以从第一天起就窃取所有私人信息,因为有人会提出过多请求,耗尽您的配额,并使您欠Google很多钱。

您需要考虑许多概念,包括限制人们不要访问不应在的地方,DOS攻击等。

我更希望客户端首先连接到您的Web服务器,在那里您将第一手防火墙,验证码,cloudflare,自定义安全性放在客户端和服务器之间,或者服务器和firebase之间,您就可以使用了。至少您可以先停止可疑活动,直到其到达火力基地。您将拥有更大的灵活性。

我只看到一种很好的使用场景,可以将基于客户端的配置用于内部使用。例如,您有内部域,并且您可以肯定外部人无法访问该域,因此可以设置浏览器-> firebase类型之类的环境。


10
但这是否与“公开”任何其他REST API相同?我的意思是使用REST API URL可供用户使用。他们可以使用URL发出他们想要的任何请求并耗尽您的配额。firebase的工作是使用api键配置,以识别您的后端部分,并且后端必须可供用户发出请求。
mbochynski

3
@mbochynski,但是您可以在某种程度上直接请求导致您付款的资源。而且在Firebase方面,没有太多的控制机制可以防止DDoS攻击等。我的建议是让您的客户端调用您的REST API,但是REST API应该私下保存API密钥,甚至在您访问Firebase资源之前,请对其进行验证如果他们是合法的要求。(通过Cloudflare等)。或从缓存中检索结果。然后,仅在需要时才打Firebase资源。这就是我想实现firebase.google.com/docs/admin/setup
泰奥曼shipahi

3
在浏览器中公开键是一个严重的坏主意。那些写所有这些指南/文章的人,他们在想什么?http Referrer的安全性?很容易被欺骗
Nick Chan Abdullah

1
你们没有考虑这个权利。不要将API密钥视为秘密。它不是私钥,而是ID,因此Firebase API知道谁在访问哪个项目。如果您需要很大的灵活性,并且需要控制服务器/客户端交互的每个步骤,那么您不应该使用Firebase,而应该使用GCP。
forresthopkinsa

@forresthopkinsa我在上面的链接中评论了采取什么方法。这里没有人天真地暗示这根本不是秘密密钥。
Teoman shipahi

4

我相信,只要数据库规则编写正确,就足以保护您的数据。此外,还有一些指南可供遵循,以相应地构建数据库。例如,在用户下创建一个UID节点,并将所有信息置于其下。之后,您将需要实现一个简单的数据库规则,如下所示

  "rules": {
    "users": {
      "$uid": {
        ".read": "auth != null && auth.uid == $uid",
        ".write": "auth != null && auth.uid == $uid"
      }
    }
  }
}

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


3

启用用户/密码注册后,API密钥公开会产生漏洞。有一个开放的API端点,该端点具有API密钥,并允许任何人创建新的用户帐户。然后,他们可以使用此新帐户登录到受Firebase Auth保护的应用,或使用SDK进行用户/通过身份验证并运行查询。

我已将此报告给Google,但他们说它正在按预期工作。

如果您不能禁用用户/密码帐户,则应执行以下操作:创建云功能以自动禁用onCreate上的新用户,并创建一个新的数据库条目来管理其访问权限。

例如:MyUsers / {userId} /访问权限:0

exports.addUser = functions.auth.user().onCreate(onAddUser);
exports.deleteUser = functions.auth.user().onDelete(onDeleteUser);

更新您的规则,以仅允许具有访问权限> 1的用户读取。

偶然的情况下,侦听器功能无法足够快地禁用帐户,然后读取规则将阻止它们读取任何数据。


3

阅读本文并研究了可能性之后,我提出了一种略有不同的方法来限制未经授权的用户使用数据:

我也将用户也保存在数据库中(并在其中保存配置文件数据)。所以我只是这样设置数据库规则:

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

这样,只有以前保存的用户才能在数据库中添加新用户,因此没有帐户的任何人都无法对数据库进行操作。仅当该用户具有特殊角色并且仅通过admin或该用户本身进行编辑时,才可以添加新用户(类似这样):

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

-2

您不应该公开此信息。在公共场合,特别是api键。这可能会导致隐私泄漏。

在将网站公开之前,您应该将其隐藏。您可以通过2种或更多方式进行操作

  1. 复杂的编码/隐藏
  2. 只需将firebase SDK代码放在您网站或应用程序的底部,firefire即可自动完成所有工作。您不需要将API密钥放在任何地方

我从Firebase引用:“将这些脚本复制并粘贴到<body>标记的底部,但在使用任何Firebase服务之前,”,其中包括API密钥
Luke-zhang-04
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.