Image

Benjamin Heald Personal Security Blog

WHOAMI and Current Resume

Blog Posts

The problem with Parse: A low-code server that endangers over 63,000,000 users.

Introduction

The Parse Platform is a popular web server similar to Firebase that allows mobile application developers to spin up a fully fledged backend with API support within a very short amount of time and with very little programming experience. Parse was created back in 2011 as a paid service that eventually shut down after being acquired by Facebook in 2017. Since then, the Parse Platform has existed as an open-source "parse server" module for Node/Express. Several popular hosting platforms offer guides on how to quickly set up a Parse Server on their infrastructure, including AWS, and Heroku.

I first became aware of Parse after encountering it while participating in a Fortune 500 internet companies' public bug bounty program. A social media application that this company created used Parse, and I was able to exploit many security issues that I later discovered were inherent to the design of the Parse Platform. In just a few days of scanning the most popular Google Play applications, I was able to discover several vulnerable Parse instances that potentially endanger the data of a collective 63,000,000 users. In this blog post I will give an overview of the many security issues inherent in the Parse platform, as well as give recommendations to both developers and the maintainers of the Parse Platform for how to improve their security posture.

Parse functionality overview

The Parse Server operates on a simple object-oriented model. All data within Parse is stored within different "objects". The developer may create their own objects or use the several default objects, such as Users to save data to. Data is queried from these objects by referencing either the object's ID number or by searching using regex. Below is a simple example of how a developer would interact with their Parse server to create a new object called Tenant.

To begin, the developer would send a POST HTTP request to their Parse server instance with their Application ID in a request header and the desired data of the object they want to insert into their database.

	  
	  POST /parse/classes/Tenant HTTP/1.1
Host: api.examplehost.com
X-Parse-Application-Id: EXAMPLE_APPLICATION_ID

{"address":"221B Baker St.","tenantName":"S. Holmes","monthlyRent":650}
	  

The Parse server will respond to this, assigning an objectId for the newly created instance of the Tenant class.

	  
	  {
  "objectId": "7ndhYbFGEW",
  "createdAt": "2020-08-23T12:45:51.080Z"
}
	  

The developer can then insert more data into the Tenant class. This process can also be done through the Parse Server GUI dashboard, as explained here.

In order to retrieve this instance of the Tenant class, it must be referenced by the Object ID, as seen below.

	  
	  GET /parse/classes/Tenant/7ndhYbFGEW HTTP/1.1
Host: api.examplehost.com
X-Parse-Application-Id: EXAMPLE_APPLICATION_ID


	  

The server will then respond with the data for that instance.

	  
	  {
  "objectId": "7ndhYbFGEW",
  "address":"221B Baker St.",
  "tenantName":"S. Holmes",
  "monthlyRent":650,
  "updatedAt": "2020-08-23T12:45:51.080Z",
  "createdAt": "2020-08-23T12:45:51.080Z"
}
	  

This next feature is where the security issues with Parse become apparent.
By issuing a GET request to the class object, the developer, or anyone else using the Parse application, can retrieve all instances of the Tenant object.

	  
	  GET /parse/classes/Tenant/ HTTP/1.1
Host: api.examplehost.com
X-Parse-Application-Id: EXAMPLE_APPLICATION_ID


	  

The server will then respond with the data for all instances of the Tenant class.

	  
	  {
  "results": [
		{
		  "objectId": "7ndhYbFGEW",
		  "address":"221B Baker St.",
		  "tenantName":"S. Holmes",
		  "monthlyRent":650,
		  "updatedAt": "2020-08-23T12:45:51.080Z",
		  "createdAt": "2020-08-23T12:45:51.080Z"
		}
		{
		  "objectId": "8sdjZcKJJH",
		  "address":"5 Main St.",
		  "tenantName":"P. Moriarty",
		  "monthlyRent":1650,
		  "updatedAt": "2020-08-23T12:45:51.080Z",
		  "createdAt": "2020-08-23T12:45:51.080Z"
		}
		{
		  "objectId": "2atxIpLMSK",
		  "address":"188 Thomas Ln.",
		  "tenantName":"I. Adler",
		  "monthlyRent":1650,
		  "updatedAt": "2020-08-23T12:45:51.080Z",
		  "createdAt": "2020-08-23T12:45:51.080Z"
		}
	]
}
	  

The problems with Parse

Data security features turned off by default

The Parse Platform goes to great lengths to enable non-technical developers to produce a full mobile application backend with little to no programming. Most if not all server setup including the class creation and insertion enumerated above can be done from their Parse Server GUI dashboard, as explained in their documentation here.

As outlined in the section above, all data stored within Parse is contained within class objects, with all user data being stored in the default users class. Obviously, the data stored within these class objects should not be searchable by default, especially if they contain sensitive information. Parse does in fact allow the developer to restrict access to these classes through the Class-Level Permissions and Object-Level Access Control. These two security features can offer a fine-grained level of control to the data stored within an instance of Parse, including preventing anonymous users from retireving all instances of a given class. Unfortunately, the information on how to use these security measures is buried on a non-central documentation page here.

The problem however is simple:

Parse Server does not enable any of these security features by default.
Even default classes that will obviously be used to contain sensitive data, such as the users class can be retrieved anonymously. To cite the Parse Server documentation:

Since these security measures are turned off by default,

All Parse class objects, including the obviously sensitive users class, can be searched and retrieved by anonymous users.

Since the Parse Platform brands itself as way in which non-technical developers can quickly and easily create a mobile application backend, it seems irresponsible to turn off all security measures by default when a major part of the clientele will not know enough about information security to implement them correctly. This hypothesis is confirmed later on in this article by observing the number of vulnerable Parse instances in the wild.

Unrestricted file upload

A second, just as dangerous vulnerability exists in the Parse Server design in the form of the File Adapter submodule. By default, all file types are allowed to be uploaded by the Parse server and uploaded files require no authentication headers to access, and can therefore be shared freely by an attacker. The only security mitigation implemented in the file upload functionality is the obfuscation of the uploaded file name. While this may prevent files uploaded to the bucket from being easily found, it does not prevent an attacker from uploading malicious files, such as HTML, to the server and sharing the URL with their victims. There are hooks that the user can program to prevent the upload of certain file types, but the documentation for this exists only for Parse Cloud, and may only be effective with that plugin. There is currently no known way to implement this through the Parse Dashboard, the GUI that many developers use to create their Parse application. This issue has been raised several times in the last five years to the developers of Parse, but has been dismissed each time:

"This is the expected behavior. Historically, on parse.com, the files upload is open to all clients."

- response to a Git issue on why Parse Server allows anonymous file upload by default. (2016)

"I'm not saying the current solution is perfect, but the obfuscation of the name is for now good enough."

- response to a Git issue on why Parse Server does not have any access control, such as authentication headers, for uploaded files. (2017)

Since most applications serve uploaded parse files from their main domain, this creates severe vulnerabilities for all users of such an application. If the application includes a cookie-based web portal on the same domain that they serve their Parse-uploaded files from, the security of all these users are put at risk from this "feature". This is again an instance of the Parse developers putting ease of development ahead of user security.

Exploiting Parse security issues

In most cases, all an attacker needs to exploit a vulnerable Parse Server is the public Parse-Application-Id. This ID string can usually be found in the application's APK files, or in the javascript of a web application. Alternatively, you could just intercept the outgoing requests from the application and retrieve it from the request headers. This ID is the only thing the Parse Server usually requires in order to both upload files and query the various class objects stored in the application. Some applications enforce that a user must have a authenticated Parse-Session-Token header as well, but these are available to all logged-in users of the application and can be easily retrieved by simply making an account on the platform.

Reading all data in a Parse class

The following POC request will return a JSON array of the User data in the Parse instance. This usually includes data like phone numbers, email addresses, full names, addresses, and sometimes even session tokens.

	  
	  GET /parse/users HTTP/1.1
Host: api.examplehost.com
X-Parse-Application-Id: EXAMPLE_APPLICATION_ID
	  

Unrestricted File Upload

If the Parse instance utilizes the File Adapter submodule, then any anonymous attacker can send the following POST request in order to upload a file of any type to the Parse instance. It should be noted that since Parse serves the uploaded files with the response header Content-Disposition: attachment;, no known RCE vulnerabilities exist here. Image and HTML files however will be served to the client in all major browsers. The following POC request will upload a TXT file to the server, with the server's response containing the fully accessible URL of the uploaded file. The file type can be changed by changing the extension in the URL or the "content-type" header.

	  
	  POST /parse/users HTTP/1.1
Host: api.examplehost.com
Content-Type: application/json; charset=utf-8
Accept: */*
X-Parse-Application-Id: EXAMPLE_APPLICATION_ID

{"limit":"1000","where":{"username":{"$regex":"@hackerone.com"}},"_method":"GET"}
	  
	  
	  HTTP/1.1 201 Created
	  
{
"url":"https://api.examplehost.com/296594f97382_test.html",
"name":"296594f97382_test.html"
}
	  
	  

The vulnerability of Parse instances in the wild

By analyzing the top 1000 android application in the social media and business categories of the Google Play store, it was found that several extremely popular application are currently using misconfigured and vulnerable Parse Server instances. A total of 63,100,000 users have downloaded this subset of vulnerable applications, which gives an idea of the impact insecure Parse servers can have. These applications were found in the space of a single afternoon with a simple Python script, and it is very likely that hundreds more applications exist, though likely with smaller user bases.

Application Type Application Downloads on the Google Play store Vulnerabilities Vendor Contacted
Mobile Game 55,000,000+ Unrestricted file upload to main domain, Read access to all User data Vendor Emailed
Social Media 5,000,000+ Unrestricted file upload to main domain Vendor Emailed
Social Media 1,000,000+ Unrestricted file upload to main domain, Read access to all User data Vendor Emailed
Productivity 1,000,000+ Read access to all User data Vendor Emailed and Contact Form
Social Media 500,000+ Read access to all User data Vendor Emailed
Dating 500,000+ Read access to all User data Vendor Emailed
Dating 100,000+ Read access to all User data Vendor Emailed

To date, none of these vendors have responded.

How to secure Parse

The good news for developers is that your Parse instance can largely be secured from the vulnerabilities listed above. Through the proper implementation of the Class-level permissions and the Object-Level access permissions as detailed in the Parse documentation here, user and other class data can be properly secured and protected against attack.

Unfortunately, in order to implement a mitigation of the unrestricted file upload vulnerability, a more complex fix will need to be implemented. This can be enforced at the bucket level, as suggested by the Parse developers. Guides on how to restrict the file upload types for some of the main hosting providers can be found here:

How Parse can improve

The idea that all security components should be enabled by default is one of the key ideas of a secure application. This is increasingly relevant in a web server that advertises itself as a low to no-code server implementation. Since a large subset of Parse users are unfamiliar with the basics of secure application development, all Parse class and object-based security measures should by default be enabled. This is especially true for the default users Parse class, which by default allows read access to all data within the class. If security features will not be implemented for all classes, they should at least be turned on by default for the users class.

Enforcing the need for authentication headers to access uploaded files would enforce ACL rules for the Parse instance and limit the possibility of an attacker sharing maliciously uploaded files with the world at large. An easy-to use security feature similar to the CLP and OLA functionality that already exists in the Parse Dashboard should also be programmed to limit the types of files that can be uploaded to the parse instance.

Conclusions

The Parse Platform provides an essential service: allowing non-technical and skilled developers to create a complex mobile application backend API with little to no programming. The usability of this service is great, and overall is a very useful product to millions of users. The security issues I have outlined above unfortunately expose glaring oversights in the security of Parse and endanger the data and security of millions. By implementing proper by-default access controls and fixing the default unrestricted file upload vulnerability, the usability and security of the Parse platform will hopefully become widespread. Please contact me at healdb2@gmail.com if you have any thoughts on Parse security, or suggestions on how I can make this guide better. Thanks for reading!

Disclaimer

The information in this article is provided “AS IS” with no warranties, and confers no rights. This article does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion. This article is intended for educational purposes only and cannot and should not be used for law violation or personal gain. The author of this project is not responsible for any possible harm caused by the materials.