In this post we'll be looking at some risks posed by Firebase, a popular serverless application platform. We'll also be introducing **[Baserunner](https://github.com/iosiro/baserunner)**, an open-source tool that helps to interact with these applications to find vulnerabilities.
- Serverless technology is becoming increasingly popular with [half of AWS users adopting Lambda](https://www.datadoghq.com/state-of-serverless/).
- It shifts some development, maintenance and security responsibilities from the developers of individual applications to their cloud service providers, such as firewalling and software updates.
- Serverless technology can also introduce its own risks. For example, by eliminating the application server and allowing front-end applications to interact directly with back-end databases, Google Cloud's Firebase creates a fail-open risk, as any database interaction which is not explicitly disallowed through security rules is allowed.
- We've developed [Baserunner](https://github.com/iosiro/baserunner), a tool that provides a convenient interface for querying the datastore of a Firebase application from an end-user's perspective to help identify security issues.
## The rise of serverless
With the rise of cloud technologies over the last decade, we hear a lot about "serverless". Having long ago made the transition from managing physical data-centers with server racks to managing elastic cloud data-centers with virtual machines, web developers and tech startups are increasingly taking the next step, away from virtual machines to cloud-native services like AWS's Elastic Beanstalk, Microsoft Azure's Managed SQL Server and Google Cloud Platform's Firebase. All of these offerings promise to cut out the need for server maintenance and, in the case of Firebase, even the need for traditional server-side application code.
While the use of serverless technologies can eliminate or at least shift the responsibility for entire swathes of traditional cybersecurity concerns, it also introduces its own set of risks.
## An overview of Firebase
The most common architecture for modern web applications comprises three main parts:
- A database of either the traditional relational kind like Postgresql, or a document store like MongoDB.
This has raised a few eyebrows among security professionals [(https://www.paladion.net/blogs/misconfigured-firebase-a-real-time-cyber-threat) , (https://www.sans.org/reading-room/whitepapers/cloud/firebase-google-clouds-evil-twin-39885)]. To give you an idea why: SQL injection is a classic web vulnerability which allows attackers to make arbitrary database queries by manipulating inputs. Put quotation marks in the right places in a vulnerable input field, and you can ask the application database to dump entire tables.
A Firebase application, by contrast, provides an API for making arbitrary database queries by design – you can run any query you want without having to mess around with unmatched quotation marks, different SQL commenting syntaxes, or the echolocation of [blind SQL injection](https://owasp.org/www-community/attacks/Blind_SQL_Injection).
Firebase's solution to this is [security rules](https://firebase.google.com/docs/rules) and tying database interaction to its user authentication model. You create rules to restrict read and write operations based on various conditions, including whether the client is authenticated and who the client is authenticated as. What would be back-end server logic in a traditional application gets built into the database in a Firebase application.
However, this can have some downsides, the most obvious of which is the propensity of the Firebase model to *fail open*. In a traditional application, the user can't interact with your database except through the API endpoints you've implemented, so the only data available to them is what you've explicitly provided them access to. In a Firebase application, all data is available to all authenticated users until you write rules restricting who can access what. [A common misconfiguration](https://www.paladion.net/blogs/misconfigured-firebase-a-real-time-cyber-threat) that used to be default allowed read and write access to *unauthenticated* users.
Discrepancies between functionality built into the front-end of a web application and functionality accessible by directly manipulating HTTP requests is a common source of web application vulnerabilities. Firebase's database API is yet another example of this. Vulnerabilities that can result from missing or insufficiently specified Firebase rules include:
- Access to sensitive data through read operations. For example, users may be able to see sensitive information about other users that is not displayed on frontend but can be queried for.
- Malicious alteration of data. For example, a user might be able to modify existing documents or add new ones that purport to come from other users or site administrators.
- Malicious deletion of data. A user might be able to delete key documents or even entire collections, rendering the application unusable.
All of the above could result from users issuing queries that are not explicitly disallowed through granular rules. In October 2020, Brandon Evans at SANS published a detailed overview of these kinds of attacks on Firebase in a whitepaper entitled ["Firebase: Google Cloud's Evil Twin"](https://www.sans.org/reading-room/whitepapers/cloud/firebase-google-clouds-evil-twin-39885).
## Introducing Baserunner
Baserunner is a minimal, generic Firebase client that allows you to load an application's configuration, log in as a valid user and issue database queries to either of Firebase's database back-ends, Cloud Firestore or Realtime Database. Cloud Firestore is similar in design to MongoDB, and Realtime Database can be thought of as a big JSON object. A Firebase application can use either or both of these datastores.
By implementing Firebase's login flow and providing a set of generic database query snippets, Baserunner aims to help security testers map out the datastores of Firebase applications and determine where additional Firebase rules need to be added to prevent abuse.
Some examples of how Baserunner can be used:
- Test read and write access to arbitrary collections from an unauthenticated perspective by running arbitrary queries without logging in.
- Attempt to dump the full datastore by running a read query on the root node of the application's Realtime Database (there is no equivalent operation for Cloud Firestore).
- Test access to restricted collections from the perspectives of users with different privilege levels to discover authorization bypass vulnerabilities (e.g. attempting to view and modify a collection of administrative site settings from a normal user's perspective).
- Test whether operations that are not available from the application front-end can be executed through direct database queries (e.g. modifying a user's account balance).
- Determine which fields in a given collection can be fetched but are not displayed by the application (e.g. a database query may return hidden IDs that could be used to discover protected content on the application).
To get started with Baserunner, [clone the repo](https://github.com/iosiro/baserunner) and follow the instructions in the README. Currently Baserunner supports both email + password and phone number + OTP login. Issues and pull requests are both welcome.