Why Firebase email/password login isn’t great for security

Tom Colvin
5 min readMar 20, 2023

--

Photo by Florian Berger

In my previous security breakdown of Firebase Auth, I noted six separate security problems, and the first on the list was its insecure password policy. Particularly, the server has almost no password complexity rules so developers are forced to implement them in their apps, which is less secure.

But it turns out that is only a part of the story.

Implementing client-side password policy is in fact more complex than it should be. The problem is that password resets are also handled insecurely, and that behaviour is hard to customise.

This article focuses on a solution for that.

Insecure password policy

Let’s remind ourselves why we have this problem in the first place.

Firebase only stipulates that passwords have to be 6 or more characters long. So the single most common password in the world — 123456 — is very much permitted server-side. There is (still!) no way to change this.

…So we have to work around it on the client side. Yes, that means implementing password policy in our apps rather than on the server. (And yes, doing so does break OWASP’s guidelines.)

Once a password policy is baked into the front-end code, it’s almost impossible to make immediate changes to it. This is more of a problem than you might think.

Say for example a new password enters the collective consciousness from a meme or a TV show. A number of users start using it, or derivations of it. So it fairly quickly enters hacker dictionaries, making it almost immediately guessable. In that situation, you will immediately want to ban that password. If policy were controlled by the server, you could do this with a single tweak to central code, which affects all apps and can be made public immediately. But when your password policy is implemented on your client apps, then every single app has to change (Android, iOS, web, …). This involves individual testing and delays as it passes through the review queue on those platforms.

But even after you’ve implemented password complexity rules on account creation in your app, there’s a further security problem lurking. This takes the form of Firebase’s password reset function.

Insecure password reset

By default, Firebase sends users who request a password reset to this mini-app:

Animated demo of entering the password ‘aaaaaa’ in the insecure password reset app
Firebase’s default password reset mini-app allows really, really dumb passwords

As you can see, it’s woefully insecure for all the reasons above. It means that even if your apps implement good password policy on account creation, each time a user resets their password they will have an opportunity to weaken it. And so gradually your user base will migrate to less secure passwords as time passes.

This default behaviour is surprisingly tricky to override.

How to override this behaviour (and why it’s tricky)

The password reset flow in Firebase Auth is:

  1. User requests password reset in the app
  2. Firebase sends the user an email with a password reset link
  3. User clicks the link and resets their password

This process is rigid, and the only customisable part is the link used in step 2.

You could change the link to point back to your app, and handle password resets there. But this can be problematic, for example when the app isn’t installed on the device which receives emails. So it’s usually better to direct users to a web-based app.

So, we have to create our own password reset mini-app for the email link to point to.

But there’s another problem. The same link used for resetting the password is also used for a whole load of other functionality including verifying your email address, resetting your email address when it’s been changed, and undoing multi-factor enrolment. So if you customise password reset you’ll also have to handle all of these, and perhaps any future functionality. It is insane that Firebase doesn’t allow you to use a different link for each, but that’s unfortunately the situation.

So, whatever mini-app we build either has to support all that functionality too, or else redirect back to the default mini-app whenever it’s not handling password resets.

Building a completely custom password reset mini-app

You can build a password reset web app using any web framework you like — there are Firebase libraries for all the major ones (e.g. AngularFire, ReactFire, VueFire) and a generic Javascript library as a catch-all. Note that you don’t have to follow the usual instructions to add Firebase; just install the right library and use the apiKey passed in (see below).

The parameters that your mini-app will be passed are:

  • mode, which tells you what action the user is trying to take and will be one of resetPassword, recoverEmail or verifyEmail
  • oobCode which is the security code needed for the functions below
  • apiKey, the Firebase instance’s API key. The fact that this is supplied to us means that we don’t actually need to hard code anything about our Firebase instance within the app. This is all that’s needed to initialise the Firebase SDK to use the API functions below.

If you are given a mode that isn’t resetPassword, then the user is trying to perform one of the other actions. You can either support that in your mini-app, too, or just redirect back to the standard one.

To redirect back to the standard app, direct the user to https://<YOUR-PROJECT-ID>.firebaseapp.com/__/auth/action , passing the same URL parameters as your app was called with.

When mode == resetPassword, the user wants to reset their password. The two API functions you will need are:

There are more details in Firebase’s official docs.

A drop-in replacement

I am working on an open-source drop-in replacement for Firebase’s mini-app which is currently here on GitHub. Once complete I will write a new article with further information. In the meantime, any community assistance is always appreciated!

Or even better…

My advice has always been to use federated login providers with Firebase. By supporting Google on Android, and Google + Apple on iPhone, you will support almost every smartphone user (note: the Chinese market is a little different). That solves the problem in one.

Federated login is more secure because other sources provide the authentication. Google and Apple (and most of the other sources Firebase Auth supports) all have complex mechanisms such as 2-factor authentication, email alerts to logins, and account lock-outs. Using a federated login source therefore applies those features to your app for free.

In conclusion, if you need to use email/password sign in on Firebase, implement password policy in-app to prevent users choosing insecure passwords, and change the default password reset behaviour to match. For all other cases, use federated login providers instead of email/password.

Tom Colvin is an Android and security specialist. He is available as a freelancer. He is the co-founder of the app development specialists Apptaura, where he builds and runs the development team.

--

--

Tom Colvin

Google Developer Expert in Android and CTO of Apptaura, the app development specialists. Available on consultancy basis. All articles 100% me, no AI.