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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37482366/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 20:22:52  来源:igfitidea点击:

Is it safe to expose Firebase apiKey to the public?

javascriptfirebase

提问by farmio

The Firebase Web-App guidestates I should put the given apiKeyin my Html to initialize 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>

By doing so, the apiKeyis exposed to every visitor. What is the purpose of that key and is it really meant to be public?

通过这样做,apiKey每个访问者都可以看到。那把钥匙的目的是什么,它真的意味着要公开吗?

回答by Frank van Puffelen

The apiKey in this configuration snippet just identifies your Firebase project on the Google servers. It is not a security risk for someone to know it. In fact, it is necessary for them to know it, in order for them to interact with your Firebase project. This same configuration data is also included in every iOS and Android app that uses Firebase as its backend.

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

In that sense it is very similar to the database URL that identifies the back-end database associated with your project in the same snippet: https://<app-id>.firebaseio.com. See this question on why this is not a security risk: How to restrict Firebase data modification?, including the use of Firebase's server side security rules to ensure only authorized users can access the backend services.

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

If you want to learn how to secure all data access to your Firebase backend services is authorized, read up on the documentation on Firebase security rules.

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



If you'd like to reduce the risk of committing this configuration data to version control, consider using the SDK auto-configuration of Firebase Hosting. While the keys will still end up in the browser in the same format, they won't be hard-coded into your code anymore with that.

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

回答by now

Building on the answers of prufrofro and Frank van Puffelen here, I put together this setup that doesn't prevent scraping, but can make it slightly harder to use your API key.

建立在prufrofro和弗兰克面包车Puffelen的答案在这里,我放在一起这个设置并不妨碍刮,但可以让它稍硬使用您的API密钥。

Warning:To get your data, even with this method, one can for example simply open the JS console in Chrome and type:

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

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

Only the database security rules can protect your data.

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

Nevertheless, I restricted my production API key use to my domain name like this:

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

  1. https://console.developers.google.com/apis
  2. Select your Firebase project
  3. Credentials
  4. Under API keys, pick your Browser key. It should look like this: "Browser key (auto created by Google Service)"
  5. In "Accept requests from these HTTP referrers (web sites)", add the URL of your app (exemple: projectname.firebaseapp.com/*)
  1. https://console.developers.google.com/apis
  2. 选择您的 Firebase 项目
  3. 证书
  4. 在 API 密钥下,选择您的浏览器密钥。它应该是这样的:“浏览器密钥(由 Google 服务自动创建)
  5. 在“接受来自这些HTTP参照请求(网站)”中,增加您的应用程序的URL(为例:projectname.firebaseapp.com/*

Now the app will only work on this specific domain name. So I created another API Key that will be private for localhost developement.

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

  1. Click Create credentials > API Key
  1. 单击创建凭据 > API 密钥

By default, as mentioned by Emmanuel Campos, Firebase only whitelists localhostand your Firebase hosting domain.

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



In order to make sure I don't publish the wrong API key by mistake, I use one of the following methods to automatically use the more restricted one in production.

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

Setup for Create-React-App

Create-React-App 的设置

In /env.development:

/env.development

REACT_APP_API_KEY=###dev-key###

In /env.production:

/env.production

REACT_APP_API_KEY=###public-key###

In /src/index.js

/src/index.js

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


My previous setup for Webpack:

我之前对 Webpack 的设置:

I use Webpack to build my production app and I put my dev API key inside my index.htmljust as you would normally do. Then, inside my webpack.production.config.jsfile, I replace the key every time index.htmlis copied to the production build:

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

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

回答by Teoman shipahi

I am not convinced to expose security/config keys to client. I would not call it secure, not because some one can steal all private information from first day, because someone can make excessive request, and drain your quota and make you owe to Google a lot of money.

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

You need to think about many concepts from restricting people not to access where they are not supposed to be, DOS attacks etc.

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

I would more prefer the client first will hit to your web server, there you put what ever first hand firewall, captcha , cloudflare, custom security in between the client and server, or between server and firebase and you are good to go. At least you can first stop suspect activity before it reaches to firebase. You will have much more flexibility.

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

I only see one good usage scenario for using client based config for internal usages. For example, you have internal domain, and you are pretty sure outsiders cannot access there, so you can setup environment like browser -> firebase type.

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

回答by Bhupiister singh

I believe once database rules are written accurately, it will be enough to protect your data. Moreover, there are guidelines that one can follow to structure your database accordingly. For example, making a UID node under users, and putting all under information under it. After that, you will need to implement a simple database rule as below

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

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

No other user will be able to read other users' data, moreover, domain policy will restrict requests coming from other domains. One can read more about it on Firebase Security rules

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

回答by Berci

After reading this and after I did some research about the possibilities, I came up with a slightly different approach to restrict data usage by unauthorised users:

在阅读完这篇文章并对可能性做了一些研究之后,我想出了一种稍微不同的方法来限制未经授权的用户使用数据:

I save my users in my DB too (and save the profile data in there). So i just set the db rules like this:

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

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

This way only a previous saved user can add new users in the DB so there is no way anyone without an account can do operations on DB. also adding new users is posible only if the user has a special role and edit only by admin or by that user itself (something like this):

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

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

回答by bzk

The API key exposure creates a vulnerability when user/password sign up is enabled. There is an open API endpoint that takes the API key and allows anyone to create a new user account. They then can use this new account to log in to your Firebase Auth protected app or use the SDK to auth with user/pass and run queries.

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

I've reported this to Google but they say it's working as intended.

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

If you can't disable user/password accounts you should do the following: Create a cloud function to auto disable new users onCreate and create a new DB entry to manage their access.

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

Ex: MyUsers/{userId}/Access: 0

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

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

Update your rules to only allow reads for users with access > 1.

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

On the off chance the listener function doesn't disable the account fast enough then the read rules will prevent them from reading any data.

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