Most applications need a database to store backend data, and Google Firebase is a great choice for serverless data management. It’s a cloud-based database hosted in Google Cloud, and it’s simple to connect from your mobile app code. Its use cases span from chat applications to easier ways to send push notifications to mobile devices to making it much easier to write files to cloud storage.
The convenience of Firebase can land developers into a minefield of mistakes, one of which is misconfiguring the Firebase database and allowing read permissions to the whole world. If you leave a Firebase database with overly permissive access, it can be stolen by anyone with an internet connection.
I’ve created a Python script to search for open Firebase databases hardcoded in source code in open repositories and scan them for publicly open read access. I’ll go over some of the code to explain it as well. You can use this script to find open Firebase databases hardcoded in any Github repository. It uses the SearchCode API to find the vulnerable repositories.
Understanding Basic Firebase Database Security
I won’t go into detail about configuring for Firebase security, but I’ll show you how to check your database if it’s open to a simple Firebase hack (if you can call it that). If your Firebase database is open to the public, you could be the target of simple Firebase hacking where a script searches and finds open databases. From there, an attacker can download all your database’s data.
Firebase databases are given a subdomain name on the firebaseio.com domain. For example, the following Firebase database is real-world example:
example.firebaseio.com
If you open that link in your browser, you’ll get redirected to the Google Firebase page. You can append “/.json” to any Firebase database URL to determine if it has read access to the public. Copy and paste the following URL into your browser:
example.firebaseio.com/.json
You’ll notice that the URL returns a JSON set from the database.
If a Firebase database is correctly configured, you should get a “Permission Denied” error instead. Let’s look at hacker-news.firebaseio.com/.json and you’ll see the correctly configured database response:
A Simple Python Database Scanning Tool
My Python scanning tool can be run with input parameter options to search only a specific repository. I’ll skip that part of the code and get to the meat of it where it iterates through a JSON dataset and finds open databases.
Here is the full script:
url = "https://searchcode.com/api/codesearch_I/?q=.firebaseio.com&p=0&per_page=50"</span> print(colored(url, 'cyan')) response = requests.get(url) res = response.json() totalRecords = res['total'] languages = res['language_filters'] results = res['results'] record = 0 previousDatabase = "" os.system('color') print("total lines found: " + str(totalRecords)) #get number of pages based on 100 output per page pages = int(totalRecords/50) #pages = 3 for i in range(pages): print("page" + str(i)) if i != 0: if flag_repo == 0: response = requests.get("https://searchcode.com/api/codesearch_I/?q=.firebaseio.com&p=" + str(i) + "&per_page=50") else: response = requests.get("https://searchcode.com/api/codesearch_I/?q=.firebaseio.com%20repo:" + repo_name + "&p=" + str(i) + "&per_page=50") res = response.json() results = res['results'] if results is None: print(colored(response.json(), 'yellow')) continue for result in results: location = result['location'] # loop through lines with firebase database</span> lines = result['lines'] for key, value in lines.items(): if ".firebaseio.com" in value: database = re.search("https://(.*?).firebaseio.com", value) if database: if database[0] != previousDatabase: previousDatabase = database[0] valid = validators.url(database[0] + "/.json") if valid: # get server response try: openDb = requests.get(database[0] + "/.json", timeout=5) except Exception as e: print(colored(e, 'yellow')) continue else: record += 1 if openDb.status_code == 200: print(colored( str(record) + ". REPO: " + result['repo'] + " LOCATION: " + location + " DB: " + database[ 0] + "/.json" + " -------->" + str(openDb.status_code), 'red')) else: print( str(record) + ". REPO: " + result['repo'] + " LOCATION: " + location + " DB: " + database[ 0] + "/.json" + " -------->" + str(openDb.status_code)) openDb.close()
A little bit about SearchCode – the API is free to use, and it searches open-source repositories across multiple platforms. You can perform a simple search using its web application too, so try it out with your own search queries.
The code above uses the SearchCode API to find all repositories with the “.firebaseio.com” string in it. SearchCode returns every repository it finds with the search string “.firebaseio.com”, gets the full URL (e.g., https://example.firebaseio.com) and then iterates through each repository search result in the “results” object. The “results” object contains lines of code where the search string is found.
For each Firebase URL found, the code performs a GET request to determine if the server response is 200 OK. If the server returns a 200 OK response, we know that the database is configured with public read access.
Output for each repository is written to the command line, but every 200 OK response is highlighted in red.
You might notice this line:
if database[0] != previousDatabase:</span> <span style="font-weight: 400;"> previousDatabase = database[0]
The SearchCode API returns all lines of code that contain the Firebase URL, and a repository could have multiple instances of the string. The above two lines of code limits calls to the internet to only a single Firebase URL reference for each repository. If a repository contains multiple Firebase URLs, it will still validate each one but only validate one instance of each URL.
In my initial search, I found about 650 public repositories with open read access on their backend Firebase database. You can use this tool to scan your own repository or perform a scan of all publicly accessible repositories available to the SearchCode API.