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