Home » Android » javascript – Is it safe to expose Firebase apiKey to the public?-Exceptionshub

javascript – Is it safe to expose Firebase apiKey to the public?-Exceptionshub

Posted by: admin February 26, 2020 Leave a comment

Questions:

The firebase Web-App guide states i should put the given apiKey in my Html to initialize 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>

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

How to&Answers:

The apiKey essentially 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.

In that sense it is very similar to the database URL that Firebase has historically been used to identify the back-end: 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.

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.

Answer:

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

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

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:

  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/* )

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

  1. Click Create credentials > API Key

This one is not restricted, so make sure you keep it private.

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


In order to make sure I don’t publish this new unrestricted API key by mistake, I use one of the following methods to automatically use the restricted one in production.

Setup for Create-React-App

In /env.development:

REACT_APP_API_KEY=

Answer:

dev-key

Answer:

In /env.production:

REACT_APP_API_KEY=

Answer:

public-key

Answer:

In /src/index.js

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

My previous setup for Webpack:

I use Webpack to build my production app and I put my dev API key inside my index.html just as you would normally do. Then, inside my webpack.production.config.js file, I replace the key every time index.html is copied to the production build:

plugins: [
    new CopyWebpackPlugin([
      {
        transform: function(content, path) {
          return content.toString().replace("

Answer:

dev-key

Answer:

", "

Answer:

public-key

Answer:

"); }, from: './index.html' } ]) ]

Answer:

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.

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.

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.

Answer:

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.

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.

Ex: 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.

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.