Firebase security checklist

To keep your Firebase resources and your users' data secure, follow these guidelines. Not every item will necessarily apply to your requirements, but keep them in mind as you develop your app.

Avoid abusive traffic

Set up monitoring and alerting for backend services

To detect abusive traffic, such as denial-of-service (DOS) attacks, set up monitoring and alerting for Cloud Firestore, Realtime Database, Cloud Storage, and Hosting

If you suspect an attack on your application, reach out to Support as soon as possible to let them know what is happening.

Enable App Check

To help ensure only your apps can access your backend services, enable App Check for every service that supports it.

Configure your Cloud Functions to scale for normal traffic

Cloud Functions automatically scales to meet your app's demands, but in the event of an attack, this can mean a big bill. To prevent this, you can limit the number of concurrent instances of a function based on normal traffic for your app.

Set up alerting to be notified when the limits are nearly reached

If your service has request spikes, often quotas will kick in, and automatically throttle traffic to your application. Make sure to monitor your Usage and billing dashboard, but you can also set budget alerts on your project to be notified when resource usage is exceeding expectations.

Prevent self-DOSes: test functions locally with the emulators

It can be easy to accidentally DOS yourself while developing Cloud Functions: for example, by creating an infinite trigger-write loop. You can prevent these mistakes from affecting live services by doing your development with the Firebase emulator suite.

(And if you do accidentally DOS yourself, undeploy your function by removing it from index.js then running firebase deploy --only functions.)

Where real-time responsiveness is less important, structure functions defensively

If you don't need to present the result of a function in real time, you can mitigate against abusive traffic by processing the results in batches: publish results to a Pub/Sub topic, and process the results at regular intervals with a scheduled function.

Understand API keys

API keys for Firebase services are not secret

Firebase uses API keys only to identify your app's Firebase project to Firebase services, and not to control access to database or Cloud Storage data, which is done using Firebase Security Rules. For this reason, you do not need to treat API keys for Firebase services as secrets, and you can safely embed them in client code. Learn more about API keys for Firebase.

Set up API key scoping

As an additional deterrent against an attacker attempting to use your API key to spoof requests, you can create API keys scoped to your app clients.

Keep FCM server keys secret

Unlike API keys for Firebase services, FCM server keys (used by the legacy FCM HTTP API) are sensitive and must be kept secret.

Keep service account keys secret

Also unlike API keys for Firebase services, service account private keys (used by the Admin SDK) are sensitive and must be kept secret.

Security rules

Initialize rules in production or locked mode

When you set up Cloud Firestore, Realtime Database, and Cloud Storage, initialize your security rules to deny all access by default, and add rules that grant access to specific resources as you develop your app.

This one of the default settings for new instances of Cloud Firestore (production mode) and Realtime Database (locked mode). Choose this option when setting up a new database instance.

For Cloud Storage, start with a security rules configuration like the following:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if false;
    }
  }
}

Security rules are a schema; add rules when you add documents

Don't write security rules after you write your app, as a kind of pre-launch task. Instead, write security rules as you write your app, treating them like a database schema: whenever you need to use a new document type or path structure, write its security rule first.

Unit test security rules with the Emulator Suite; add it to CI

To make sure your security rules are keeping up with your app's development, unit test your rules with the Firebase emulator suite and add these tests to your CI pipeline. See these guides for Cloud Firestore and Realtime Database.

Authentication

Custom authentication: mint JWTs from a trusted (server-side) environment

If you already have a secure sign-in system, whether a custom system or a third-party service, you can use your existing system to authenticate with Firebase services. Create custom JWTs from a trusted environment, then pass the tokens to your client, which uses the token to authenticate (iOS+, Android, Web, Unity, C++).

For an example of using custom authentication with a third-party provider, see the blog post, Authenticate with Firebase using Okta.

Managed authentication: OAuth 2.0 providers are the most secure

If you use Firebase's managed authentication features, the OAuth 2.0 / OpenID Connect provider options (Google, Facebook, etc.) are the most secure. You should support one or more of these providers if you can (depending on your user base).

Email-password authentication: set tight quota for the sign-in endpoint to prevent brute force attacks

If you use Firebase's managed email-password authentication service, tighten the default quota of the identitytoolkit.googleapis.com endpoints to prevent brute force attacks. You can do so from the API's page in the Google Cloud console.

Email-password authentication: Enable email enumeration protection

If you use Firebase's managed email-password authentication service, enable email enumeration protection, which prevents malicious actors from abusing your project's auth endpoints to guess account names.

Upgrade to Cloud Identity Platform for multi-factor authentication

For extra security on sign-in, you can add multi-factor authentication support by upgrading to Cloud Identity Platform. Your existing Firebase Authentication code will continue to work after you upgrade.

Anonymous authentication

Only use anonymous authentication for warm onboarding

Only use anonymous authentication to save basic state for users before they actually sign in. Anonymous authentication is not a replacement for user sign-in.

Convert users to another sign-in method if they’ll want the data when they lose their phone

Anonymous authentication data will not persist if the user clears local storage or switches devices. If you need to persist data beyond app restarts on a single device, convert the user to a permanent account.

Use security rules that require users to have converted to a sign in provider or have verified their email

Anyone can create an anonymous account in your project. With that in mind, protect all non-public data with security rules that require specific sign-in methods or verified email addresses.

For example:

allow write: if request.auth.token.firebase.sign_in_provider != "anonymous";
allow write: if request.auth.token.email_verified = true;

Environment management

Set up development and staging projects

Set up separate Firebase projects for development, staging, and production. Don't merge client code to production until it's been tested against the staging project.

Limit team access to production data

If you work with a larger team, you can mitigate the consequences of mistakes and breaches by limiting access to production data using either predefined roles or custom IAM roles.

If your team uses the emulator suite for development, you might not need to grant wider access to the production project.

Library management

Watch out for library misspellings or new maintainers

When adding libraries to your project, pay close attention to the name of the library and its maintainers. A similarly-named library to the one you intend to install could contain malicious code.

Don’t update libraries without understanding the changes

Look over the change logs of any libraries you use before you upgrade. Be sure the upgrade adds value, and check that the maintainer is still a party you trust.

Install watchdog libraries as dev or test dependencies

Use a library such as Snyk to scan your project for insecure dependencies.

Set up monitoring for Functions; check it after library updates

If you use the Cloud Functions logger SDK, you can monitor and be alerted of unusual behavior, including behavior caused by library updates.

Cloud Function safety

Never put sensitive information in a Cloud Function’s environment variables

Often in a self-hosted Node.js app, you use environment variables to contain sensitive information like private keys. Do not do this in Cloud Functions. Because Cloud Functions reuses environments between function invocations, sensitive information shouldn't be stored in the environment.

  • To store Firebase API keys, which are not secret, just embed them in code.
  • If you're using the Firebase Admin SDK in a Cloud Function, you don't need to explicitly provide service account credentials, because the SDK can automatically acquire them during initialization.
  • If you're calling Google and Google Cloud APIs that require service account credentials, the Google Auth library for Node.js can get these credentials from the application default credentials, which are automatically populated in Cloud Functions.
  • To make private keys and credentials for non-Google services available to your Cloud Functions, use Cloud Secret Manager.

Encrypt sensitive information

If you can't avoid passing sensitive information to your Cloud Function, you must come up with your own custom solution to encrypt the information.

Simple functions are safer; if you need complexity, consider Cloud Run

Try to keep your Cloud Functions as simple and understandable as possible. Complexity in your functions can often lead to hard-to-spot bugs or unexpected behavior.

If you do need complex logic or environment configurations, consider using Cloud Run instead of Cloud Functions.