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

Posted

技术标签:

【中文标题】向公众公开 Firebase apiKey 是不是安全?【英文标题】:Is it safe to expose Firebase apiKey to the public?向公众公开 Firebase apiKey 是否安全? 【发布时间】:2020-06-06 01:53:03 【问题描述】:

Firebase Web-App guide 声明我应该将给定的apiKey 放在我的 html 中以初始化 Firebase:

// 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 会暴露给每个访问者。

该密钥的用途是什么?它真的是打算公开吗?

【问题讨论】:

用户 Christophe Quintard 添加了一个非常有用的文章的链接,其中包含有关 Firebase API 安全性的其他信息,因此我将其重新发布在此处:javebratt.com/hide-firebase-api(评论正在消失,因为它附加到另一个用户的答案,由于质量差而被标记为删除) 我只想指出,仅仅因为这个特定的框架恰好可以暴露它的 API,这并不意味着其他框架可以接受它。不希望任何人带着“可以公开 API 密钥”的想法离开这篇文章。 您可以毫无问题地公开密钥。为了安全起见,您可以在生产中使用特定域对其进行限制,这样其他人就无法从任何随机域名进行调用 API 调用。为了更安全,从生产应用程序中删除 localhost。 我不认为从你的推荐人白名单中删除 localhost 会做任何事情,除了让测试更难。该配置不像 IP 白名单。把它想象成一个 CORS 配置。 Firebase 的工作方式是这些 API 路由直接从客户端调用,它们没有被代理。这就是您的网页需要 API 密钥的原因。如果一个坏演员想从 Postman 调用你的 API 路由,你的推荐人白名单不会阻止他们。它仅用于防止其他公共网站从您的服务器上闲逛。 如果您想阻止对手通过 CURL 滥用您的 API,那么您需要实施其他对策,例如身份验证和速率限制。这是一个面向互联网的 API。这是好事!!不是错误,是功能。 【参考方案1】: 推荐的答案 Google Cloud

此配置 sn-p 中的 apiKey 仅标识您在 Google 服务器上的 Firebase 项目。有人知道它不是安全风险。事实上,他们有必要知道它,以便他们与您的 Firebase 项目进行交互。每个使用 Firebase 作为后端的 iosandroid 应用程序也包含相同的配置数据。

从这个意义上说,它与在同一个 sn-p 中标识与您的项目关联的后端数据库的数据库 URL 非常相似:https://&lt;app-id&gt;.firebaseio.com。请参阅此问题,了解为什么这不是安全风险:How to restrict Firebase data modification?,包括使用 Firebase 的服务器端安全规则来确保只有授权用户才能访问后端服务。

如果您想了解如何确保对 Firebase 后端服务的所有数据访问都获得授权,请阅读Firebase security rules 上的文档。这些规则控制对文件存储和数据库的访问,并在 Firebase 服务器上强制执行。所以无论是你的代码,还是其他人的代码使用你的配置数据,它只能做安全规则允许它做的事情。

有关 Firebase 将这些值用于什么目的以及您可以为哪些设置配额的其他说明,请参阅 using and managing API keys 上的 Firebase 文档。


如果您想降低将此配置数据提交给版本控制的风险,请考虑使用SDK auto-configuration of Firebase Hosting。虽然密钥仍会以相同的格式出现在浏览器中,但它们不会再被硬编码到您的代码中。


更新(2021 年 5 月):借助名为 Firebase App Check 的新功能,现在实际上可以将 Firebase 项目中后端服务的访问权限限制为仅来自 iOS、Android 的后端服务以及在该特定项目中注册的 Web 应用程序。

您通常希望将此与上述基于用户身份验证的安全性结合起来,这样您就有了另一个屏障,可以防止确实使用您的应用的滥用用户。

通过将 App Check 与安全规则相结合,您既可以防止滥用,又可以很好地控制每个用户可以访问的数据,同时仍然允许从客户端应用程序代码直接访问数据库。

【讨论】:

所以这意味着其他人将能够访问我的 firebase 数据库中的所有数据? @EmmanuelCampos 答案是“是”和“否”。是的,如果您允许或希望其他人访问数据库中的所有数据。不,如果你不希望他们这样做。 Firebase 数据库有规则,你可以控制的规则 在这里找到了我最后一个问题的答案support.google.com/firebase/answer/6400741 感谢您的帮助。此链接将来可能会对某人有所帮助。 @m.rufca ,您的数据应该可供经过身份验证的用户使用。这就是诀窍。默认情况下,在您的 Firebase 设置中,只有 localhost 和您的项目域有权从它们执行身份验证。因此,没有其他人可以创建通常可以与您的 Firebase 一起使用的应用程序。 如果机器人在我的应用程序中创建无限用户怎么办。我怎样才能要求验证码。【参考方案2】:

根据 prufrofro 和 Frank van Puffelen here 的回答,我整理了这个设置,它不会阻止抓取,但会使使用您的 API 密钥变得更加困难。

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

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

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

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

    https://console.developers.google.com/apis 选择您的 Firebase 项目 凭据 在 API 密钥下,选择您的浏览器密钥。它应该如下所示:“浏览器键(由 Google 服务自动创建)” 在“接受来自这些的请求 HTTP 引荐来源网址(网站)”,添加您的应用的 URL(例如:projectname.firebaseapp.com/*

现在该应用程序将仅适用于该特定域名。因此,我创建了另一个 API 密钥,将用于 localhost 开发。

    单击创建凭据 > API 密钥

默认情况下,如 Emmanuel Campos 所述,Firebase only whitelists localhost and your Firebase hosting domain。


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

Create-React-App 的设置

/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,
  // ... 
;

【讨论】:

这对你有用吗?正在考虑为 Android 应用程序做同样的事情。我想知道为什么 Firebase 没有在安全部分涵盖这一点。 到目前为止我没有遇到任何问题,但可能也没有攻击 这在他们的指南中没有提到,因为它不会保护你免受刮擦。所有这一切都确保了其他人无法制作使用您的 Firebase 来读取(或写入)数据的网络应用程序,如果它在正常运行良好的浏览器中运行。 在“接受来自这些 HTTP 引荐来源网址(网站)的请求”中,添加您的应用的 URL(例如:projectname.firebaseapp.com/*)这不起作用。 @FrankvanPuffelen 据我了解,这并没有什么大的区别,但滥用配额可能会更烦人,因为在表现良好的浏览器中,API 密钥与 HTML 一起提供/JS 仅适用于预期的域,而不适用于 localhost 或其他任何内容。但我同意与 Firebase 已经提供的保护相比,增加的保护是微不足道的。我会改写一些不太戏剧化的答案。【参考方案3】:

我不相信向客户端公开安全/配置密钥。我不会说它安全,不是因为有人可以从第一天就窃取所有私人信息,因为有人可以提出过多的要求,耗尽你的配额,让你欠谷歌很多钱。

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

我更希望客户端首先访问您的 Web 服务器,您可以在客户端和服务器之间或服务器和 firebase 之间放置任何第一手防火墙、验证码、cloudflare、自定义安全性,然后您就可以开始使用了.至少您可以在可疑活动到达火力基地之前先停止它。您将拥有更大的灵活性。

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

【讨论】:

但这与“公开”任何其他 REST API 不一样吗?我的意思是用户可以使用 REST API URL。他们可以使用 URL 发出他们想要的任何请求并耗尽您的配额。 firebase 所做的是使用带有 api 密钥的配置来识别您的后端部分,并且它必须可供用户发出请求。 @mbochynski 但您可以在某种程度上直接请求资源,从而导致您付费。在 Firebase 方面,没有太多的控制机制来防止 DDoS 攻击等。我的建议是让您的客户端调用您的 REST API,但 REST API 应该私下持有 API 密钥,甚至在您访问 Firebase 资源之前,验证它们如果他们是合法的请求。 (通过 Cloudflare 等)。或从缓存中检索结果。然后,只有在需要时才使用 Firebase 资源。这就是我要实现的firebase.google.com/docs/admin/setup 在浏览器中公开密钥是一个非常糟糕的主意。那些写所有这些指南/文章的人,他们在想什么? http 推荐人的安全性?很容易被欺骗 你们没有考虑这个权利。不要将 API Key 视为秘密;它不是私钥,它只是一个 ID,因此 Firebase API 知道谁在访问哪个项目。如果您想要很大的灵活性并且需要控制服务器/客户端交互的每一步,那么您不应该使用 Firebase,而应该使用 GCP。 @forresthopkinsa 我有上面的链接评论采取什么方法。这里没有人天真地认为它是一个秘密密钥。【参考方案4】:

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

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

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

例如:MyUsers/userId/访问:0

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

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

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

【讨论】:

你说的是哪个 API? @VaibS Firebase 身份验证 REST API firebase.google.com/docs/reference/rest/auth 如果我们只将我们的域列入白名单,这仍然是一个问题吗?【参考方案5】:

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

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

其他用户将无法读取其他用户的数据,此外,域策略将限制来自其他域的请求。 可以阅读更多关于它的信息 Firebase Security rules

【讨论】:

【参考方案6】:

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

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

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

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

只有当用户具有特殊角色并且只能由管理员或该用户自己编辑(类似这样)时,才可以添加新用户:

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

【讨论】:

【参考方案7】:

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

开放的 api 密钥会导致攻击,这些攻击可能会在 firebase 上使用大量资源,这肯定会花费您的血汗钱。

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

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

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

【讨论】:

【参考方案8】:

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

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

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

欲了解更多信息,请查看the offical docs

【讨论】:

【参考方案9】:

我正在 github 页面上创建一个博客网站。我想在每个博客页面的末尾嵌入 cmets。我了解 firebase 如何获取数据并为您提供数据。

我已经用项目测试过很多次,甚至使用过控制台。我完全不同意 vlit 是脆弱的说法。 相信我,如果您遵循 firebase 推荐的隐私步骤,公开显示您的 api 密钥是没有问题的。 转至https://console.developers.google.com/apis 并执行安全步骤。

【讨论】:

【参考方案10】:

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

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

    复杂的编码/隐藏 只需将 firebase SDK 代码放在您的网站或应用程序的底部,这样 firebase 就会自动完成所有工作。您无需将 API 密钥放在任何地方

【讨论】:

我引用 Firebase 的话,“在您使用任何 Firebase 服务之前,将这些脚本复制并粘贴到您的 标记的底部”,其中包括 API 密钥

以上是关于向公众公开 Firebase apiKey 是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

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

获取 apiKey 到 firebase

我在哪里可以找到我的 Firebase apiKey 和 authDomain

react native android中的firebase apikey丢失或无效

如何使用 apollo Reactjs 客户端刷新 Firebase IdToken

如何使用firebase更改flutter项目中的API KEY?