Parse Security V – How to Make Friends

In the first four parts of this five-part series on how to secure your Parse app, we’ve taken a look at all of the different features that Parse has to help you secure your app and your users’ data. In Part V, let’s put it all together and take a look at a real example of how you can use these features to solve a complex use case.

Most classes in your app will fall into one of a couple of easy-to-secure categories. For fully public data, you can use class-level permissions to lock down the table to put publicly readable and writeable by no one. For fully private data, you can use ACLs to make sure that only the user who owns the data can read it. But occasionally, you’ll run into situations where you don’t want data that’s fully public or fully private. For example, you may have a social app, where you have data for a user that should be readable only to friends whom they’ve approved. For this you’ll need to use ACLs, roles, and Cloud Code together to enable exactly the sharing rules you desire.

If you aren’t clear on those features, go back and read Parts II – IV of this series. Once you’re clear on what ACLs, roles, and Cloud Code are, let’s dig into some code. The first thing you’ll need to do is set up a place for the user’s social data to live. Let’s assume you want to create a “FriendData” object for each user that stores the data that should be visible to their friends. To create this object for each new user, you can use an afterSave handler.

Parse.Cloud.afterSave(Parse.User, function(request, response) {
    var user = request.object;
    if (user.existed()) { return; }
    var roleName = "friendsOf_" + user.id;
    var friendRole = new Parse.Role(roleName, new Parse.ACL(user));
    return friendRole.save().then(function(friendRole) {
        var acl = new Parse.ACL();
        acl.setReadAccess(friendRole, true);
        acl.setReadAccess(user, true);
        acl.setWriteAccess(user, true);
        var friendData = new Parse.Object("FriendData", {
          user: user,
          ACL: acl,
          profile: "my friend profile"
        });
        return friendData.save();
    });
});

The first couple of lines just set up the request. On line 3, we check to see if the user already existed. If so, then we’ve already completed this setup, and there’s no reason to do it again. On lines 4-6, we create a new role. This role will represent the friends of the user being created. We generate a unique name for the role. The role is created with an ACL that only allows this user to read or write it. In other words, only the user themselves can decide who their friends are.

Once the role is created, lines 7-10 create an ACL that grants read permission to friends of the user. And of course the user receives read and write permission for their own social data. Once the ACL is set up, lines 11-16 actually create the object. The user is set on the object so that it can be found with a query later. The profile field is set as an example of data that will be readable only to the users friends.

So, that’s everything you need to set up an object for every user that will be readable only to people in their special friends role. Of course, that’s worthless without any way for people to get added to your friends list, so we need to address that with another function. Technically, this function could be written in any client and be secure, but for the sake of consistency, let’s make another Cloud Code function. This function will be called “friend.”  It will take one parameter: the objectId of the person to friend. This person will then be added to the friends role of the current user.

Parse.Cloud.define("friend", function(request, response) {
    var userToFriend = new Parse.User();
    userToFriend.id = request.params.friendId;

    var roleName = "friendsOf_" + request.user.id;
    var roleQuery = new Parse.Query("_Role");
    roleQuery.equalTo("name", roleName);
    roleQuery.first().then(function(role) {
        role.getUsers().add(userToFriend);
        return role.save();

    }).then(function() {
        response.success("Success!");    
    });
});

Lines 1-3 just set up the function and create a User object to represent the person being added to the friend role. Lines 5-8 fetch the Role object using its name. A Role is just a special kind of Parse object, so we need to fetch it before we can modify it. Once the role has been fetched, we add this user to it on line 9, and save it on line 10. That’s all there is to it! Now we have an easy way to store data that’s only accessible to a user’s friends.

Over the course of this five-part series on how to secure your Parse app, we’ve looked at a lot of features. You know the about the various keys used to access your app. We’ve looked at the permissions you can set to lock down a whole class. You’ve learned about ACLs and how they can secure per-user data. And we’ve even dived deep into a particular example of how you can use Cloud Code to tackle even the trickiest data models.

We hope that you’ll use these tools to do everything you can to keep your app’s data and your users’ data secure. Together, we can make the web a safer place.

Bryan Klimt
July 28, 2014

Red Bull Brings Its A-Game to Mobile With Parse Core

Red Bull WallpapersWhile some reach for Red Bull on the shelves of beverage aisles, the global brand itself has reached far beyond the boundaries of any storefront. Since 2007, the Red Bull Media House has been constantly seeking innovative ways to expand the boundaries of the user experience that is the Red Bull brand. From its inception, Red Bull Media House sought to establish itself as a multi-platform media company with a focus on sports, culture, and lifestyle. Given the wide range of media products housed across its umbrella brand, Red Bull Media House began to double down on app development in 2009 in search of ways to tie them all together. Today, Red Bull Media House has put 30 apps to market across all platforms.

Its latest hit, Red Bull Wallpapers, is a demonstration of Red Bull’s incredibly unique offerings, and of its ability to bring them together in innovative ways with Red Bull Media House. With the use of Parse Core, Red Bull Wallpapers brings captivating imagery from the World of Red Bull straight to the palm of a user’s hand. Android users can customize their home and lock screens with static wallpapers or with animated and enhanced live wallpapers of their favorite Red Bull athletes. Other choices include photos from sports including motocross, motorsports such as Formula One, skateboarding, surfing, skiing, BMX, and more.

In order to deliver such high-quality sports photography to its mobile users, Red Bull Media House utilizes Parse Core to store and load all wallpaper-related data. This includes the name of the athlete or the photographer credits. The data browser is also used for analytics, insights, and updating the use count.  With the use of Parse, development time is saved on the server side, enabling developers to focus even more strongly on the core aspects such as quality and content of the app.

Alongside the release of Red Bull Wallpapers, the brand has become more prominent than ever by tackling all perspectives of a customer’s daily life. From the home screen to the big screen and beyond, experiences such as the one offered by Red Bull Wallpapers provide an inspiring extension of the Red Bull brand.

Nancy
July 25, 2014

Parse Security IV – Ahead in the Cloud

In our first three posts on how to secure your Parse app, we looked at your app’s keys, class-level permissions, and object-level ACLs. For many apps, that’s all you need to keep your app and your users’ data safe. But sometimes you’ll run into an edge case where they aren’t quite enough. For everything else, there’s Cloud Code.

With Cloud Code, you can upload JavaScript to Parse’s servers, where we will run it for you. Unlike client code running on users’ devices that may have been tampered with, Cloud Code is guaranteed to be the code that you’ve written, so it can be trusted with more responsibility. For example, if you need to validate the data that a user has entered, you should do it in Cloud Code so that you know a malicious client won’t be able to bypass the validation logic. Specifically to help you validate data, Cloud Code has beforeSave triggers. These triggers are run whenever an object is saved, and allow you to modify the object, or completely reject a save. For example, this is how you create a Cloud Code trigger to make sure every user has an email address set:

Parse.Cloud.beforeSave(Parse.User, function(request, response) {
  var user = request.object;
  if (!user.get("email")) {
    response.error("Every user must have an email address.");
  } else {
    response.success();
  }
});

To upload this trigger, follow the instructions in our guide for setting up the Parse command line tool.

You can also use your master key in Cloud Code to bypass the normal security mechanism for trusted code. For example, if you want to allow a user to “like” a “Post” object without giving them full write permissions on the object, you can do so with a Cloud Code function. Every API function in the Cloud Code JavaScript SDK that talks to Parse allows passing in a useMasterKey option. By providing this option, you will use the master key for that one request.

Parse.Cloud.define("like", function(request, response) {
  var post = new Parse.Object("Post");
  post.id = request.params.postId;
  post.increment("likes");
  post.save(null, { useMasterKey: true }).then(function() {
    response.success();
  }, function(error) {
    response.error(error);
  });
});

One very common use case for Cloud Code is sending push notifications to particular users. In general, clients can’t be trusted to send push notifications directly, because they could modify the alert text, or push to people they shouldn’t be able to. Your app’s settings will allow you to set whether “client push” is enabled or not; we recommend that you make sure it’s disabled. Instead, you should write Cloud Code functions that validate the data to be pushed before sending a push.

In this post, we’ve looked at how you can use Cloud Code to write trusted code, to keep your data secure in cases where class-level permissions and ACLs aren’t enough. In Part V, we’ll dive into a particular example of how to use ACLs, Roles, and Cloud Code to let users have data that is shared only to their friends.

Bryan Klimt
July 21, 2014

Wargaming’s World of Tanks Blitz Uses Parse Push to Keep Users Engaged

Wargaming takes the world by storm once more with the release of World of Tanks Blitz onto iOS.  Wildly popular on desktop, World of Tanks has attracted more than 85 million players from all corners of the globe.  Now, Wargaming has put the franchise directly into the hands of its players, running on iPad 2 and up or iPhone 4S and up.  Featuring over 90 tanks from Russia, Germany, and the U.S., players can challenge each other in synchronous 7-on-7 matches.

Since its release, gamers have been spending an average of 70 minutes in the game. With player engagement and long-term retention representing a core challenge, Andrey Ryabovol, Director of Global Operations at World of Tanks, turned to Parse to power push notifications as part of their strategy.

Screenshot OneScreenshot Two

Wargaming sought to develop its mobile version of World of Tanks Blitz from the ground up.  Rather than making a port of the PC game, the team uniquely tailored the controls and experience towards use on a smartphone or tablet.  However, building their own notification solution would have taken significant resources and time. By leveraging Parse Push, Wargaming was able to focus on product development and the messaging behind keeping players informed and active in the game. High quality, targeted push notifications are crucial to keeping players engaged, especially throughout World of Tanks Blitz’s 10 tiers of gameplay.  Parse Push will also be used to announce the sale of exclusive in-game items, such as premium, high-end tanks.  As Andrey explains:

Parse Push is the ideal solution for us because it is easy to adapt to our business needs.  We have a lot of data, putting a lot of pressure on the system, so Parse was the perfect solution for data management. We consider our cooperation with Parse and Facebook as a long-term strategic partnership.

World of Tanks Blitz is available for iOS on the App Store.  See you on the battlefield!

Ali
July 18, 2014

Parse Security III – Are You On the List?

In Part II, we looked at class-level permissions, which allow you to quickly set permissions for an entire class at once. But often, the different objects in a class will need to be accessible by different people. For example, a user’s private personal data should be accessible only to them. For that, you have to use an Access Control List, usually referred to as an ACL. If you have a production app and you aren’t using ACLs, you’re almost certainly doing it wrong.

An ACL specifies a set of users who can read or write an object’s data. So, before you can use ACLs, you have to have Users. There are many ways to handle users on Parse. You can have usernames and passwords, or you can use Facebook Login. If you don’t want to make your users create usernames just to log in, you can even use Parse’s automatic anonymous users feature. That allows you to create a user and log them in on a particular device in a secure way. If they later decide to set a username and password, or link the account with Facebook, then they can then log in from any other device. Setting up automatic anonymous users is easy, so you have no excuse not to protect per-user data!

[PFUser enableAutomaticUser];

Once you have a user, you can start using ACLs. To set an ACL on the current user’s data to not be publicly readable, all you have to do is:

PFUser *user = [PFUser currentUser];
user.ACL = [PFACL ACLWithUser:user];

Most apps should do this. If you store any sensitive user data, such as email addresses or phone numbers, you need to set an ACL like this so that the user’s private information isn’t visible to other users. If an object doesn’t have an ACL, it’s readable and writeable by everyone. The only exception is the _User class. We never allow users to write each other’s data, but they can read it by default. (If you as the developer need to update other _User objects, remember that your master key can provide the power to do this.) To make it super easy to create user-private ACLs for every object, we have a way to set a default ACL that will be used for every new object you create.

[PFACL setDefaultACL:[PFACL ACL] withAccessForCurrentUser:YES];

If you want the user to have some data that is public and some that is private, it’s best to have two separate objects. You can add a pointer to the private data from the public one.

PFObject *privateData = [PFObject objectWithClassName:@"PrivateUserData"];
privateData.ACL = [PFACL ACLWithUser:[PFUser currentUser]];
[privateData setObject:@"555-5309" forKey:@"phoneNumber"];

[PFUser setObject:privateData forKey:@"privateData"];

Of course, you can set different read and write permissions on an object. For example, this is how you would create an ACL for a public post by a user, where anyone can read it:

PFACL *acl = [PFACL ACL];
[acl setPublicReadAccess:true];
[acl setWriteAccess:true forUser:[PFUser currentUser]];

Sometimes, it’s inconvenient to manage permissions on a per-user basis, and you want to have groups of users who get treated the same. For example, your app may have a group of admins who are the only ones who can write data. Roles are are a special kind of object that let you create a group of users that can all be assigned to the ACL. The best thing about roles is that you can add and remove users from a role without having to update every single object that is restricted to that role. To create an object that is writeable only by admins:

PFACL *acl = [PFACL ACL];
[acl setPublicReadAccess:true];
[acl setWriteAccess:true forRoleWithName:@"admins"];

Of course, this snippet assumes you’ve already created a role called “admins”. In many cases, this is reasonable, because you have a small set of special roles you can set up while developing your app. But sometimes you will need to create roles on the fly. In a future blog post, we’ll look into how you can use ACLs and roles to manage a user’s data so that it will only be visible to their friends.

So far in this security series, we’ve covered class-level permissions and ACLs. These features are sufficient to secure the vast majority of apps. In Part IV, we’ll look at how you can use Cloud Code to secure apps even in rare edge cases.

Bryan Klimt
July 14, 2014

Groupon Taiwan Uses Parse Push to Offer Deals with Ease

Groupon Taiwan

Discovering the best of a city, planning a vacation, and searching a specially curated selection of electronics, fashion, and home furnishings is easier than ever with the scale of Groupon.  As a global leader of local commerce, Groupon has emerged as one of the most powerful channels on earth for consumers to find and enjoy unbeatable deals.

Groupon’s extensive reach is especially acute through its Groupon Taiwan market.  By redefining how traditional small businesses attract, retain, and interact with customers, Groupon Taiwan has become not only a key destination for consumers, but a key tool for merchants as well.  Mobile purchases have surged, and with it, Groupon Taiwan’s crucial need to develop a comprehensive, cross-platform app to build a closer relationship with their customers.

Since the launch of Groupon Taiwan’s site, both Parse and Facebook Login have served as standout components of their success.  The Groupon Taiwan app saw thousands of downloads per week after its initial release.  Facebook Login has played a key role in saving customers’ time during the registration process.  According to Groupon Taiwan’s lead UI designer,

Facebook Login saved our users’ time during the registration process, making it that much easier for a new user to make their first purchase.

Simultaneously, Parse Push has helped to retain those users and drive a much deeper, long-term relationship with Groupon Taiwan customers.  Parse Push streamlines the process for Groupon Taiwan to contact its customers, especially given the time-sensitive nature of its highly sought-after deals.  For Groupon Taiwan, the use of Parse has been a reliable way to tackle retention and user communication,

We use Parse to push hot deals to our customers.  It’s quick and cost-saving, and a direct way to reach our app users.

As Groupon continues to scale internationally, Taiwan is a market that has established an efficient and easy-to-implement method of regularly connecting with its devoted customer base through its use of Parse Push.  Groupon Taiwan is available for download in the Google Play Store and in the App Store.

Nancy
July 11, 2014

Parse Security II – Class Hysteria!

In Part I, we took a look at the different keys that a Parse app has and what they mean. As we learned, your client keys are easily accessible to anybody, so you need to rely on Parse’s security features to lock down what the client key is allowed to do.

The easiest way to lock down your app is with class-level permissions. Almost every class that you create should have these permissions tweaked to some degree. For classes where every object has the same permissions, class-level settings will be most effective. For example, one common use case: having a class of static data that can be read by anyone but written by no one. If you need different objects to have different permissions, you’ll have to use ACLs–Access Control Lists–(discussed in Part III). To edit your class-level permissions, click on “Set permissions” under the “More” menu in the Data Browser for the class you want to configure.

Set permissions menu

For each setting, you can choose to either leave it open to everyone, or to restrict it to certain predefined Roles or Users. A Role is simply a set of Users and Roles who should share some of the same permissions. For example, you can set up a Role called “admins” and make a table writeable only by that role.

Class-level Permissions

Let’s go over what each permission means.

  • Get – With Get permission, users can fetch objects in this table if they know their objectIds.
  • Find – Anyone with Find permission can query all of the objects in the table, even if they don’t know their objectIds. Any table with public Find permission will be completely readable by the public, unless you put an ACL on each object.
  • Update – Anyone with Update permission can modify the fields of any object in the table that doesn’t have an ACL. For publicly readable data, such as game levels or assets, you should disable this permission.
  • Create – Like Update, anyone with Create permission can create new objects of a class. As with the Update permission, you’ll want to turn this off for publicly readable data.
  • Delete – This one should be pretty obvious. With this permission, people can delete any object in the table that doesn’t have an ACL. All they need is its objectId.
  • Add fields -This is probably the strangest permission. Parse classes have schemas that are inferred when objects are created. While you’re developing your app, this is great, because you can add a new field to your object without having to make any changes on the backend. But once you ship your app, it’s very rare to need to add new fields to your classes automatically. So you should pretty much always turn off this permission for all of your classes when you submit your app to the public.

There’s also an app-level permission to disable client class creation. You should turn this off for production app so that clients can’t create new classes. Usually this isn’t a big security risk, but it’s nice to stop malicious people from creating new tables that you’ll see in the data browser.

Client Class Creation

Class-level permissions are great for globally-shared data where permissions for each object in the class should be exactly the same. In Part III, we’ll learn about ACLs, which allow you to have different permissions for each object in a class.

Bryan Klimt
July 7, 2014

Parse Security I – Are you the Key Master?

So, you’ve finished version 1 of your app, and you’re ready to send it out into the world. Like a child leaving the nest, you are ready to push your app out to the various app stores and wait for the glowing reviews to come streaming in. Not so fast! You wouldn’t send a child out into the world without teaching them how to protect themselves. Likewise, you shouldn’t send your app out into a user’s hands without taking some time to secure it using industry-standard best practices. After all, if your app gets compromised, it’s not only you who suffers, but potentially the users of your app as well. In this five-part series, we’ll take a look at what you can do to secure your Parse app.

Parse App Keys

Security starts with understanding your app’s keys. A Parse app has several different keys: a client key, a REST key, a .NET key, a JavaScript key, and a master key. All of the keys–other than the master key–have basically the same permissions. They are just intended for use on different platforms. So, we usually refer to any of those keys as a “client key.” The first thing you need to understand is that your client key is not a security mechanism. It’s not even intended to serve as such. Your client key is shipped as a part of your app. Anyone can decompile your app or proxy network traffic from their device and see your client key. With JavaScript, it’s even easier. One can simply “view source” in the browser and immediately know your key. That’s why Parse has many other security features to help you secure your data. The client key is given out to your users, so anything that can be done with just the client key is doable by the general public, even malicious hackers.

The master key, on the other hand, is definitely a security mechanism. Using the master key allows you to bypass all of your app’s security mechanisms, such as class-level permissions and ACLs. Having the master key is like having root access to your app’s servers. You should guard your master key with the same zeal with which you would guard your production machines’ root password. Never check your master key into source control. Never include your master key in any binary or source code you ship to customers. And above all, never, ever give your master key out to strangers in online chat rooms. Stranger danger!

In Part II, we’ll take a look at Parse’s advanced features, which allow you to control what people with your client key can do.

Bryan Klimt
June 30, 2014

FOX International Channels Scores Another Goal with Parse

Following the widespread success of its last two app releases, FOX Sports has not missed a beat with Destino Brasil.  As the best app to accompany users while they enjoy the best of Brazil, Destino Brasil entails a comprehensive experience for any soccer fan.  Users can view live schedules, add games to their calendars, and even participate live on the TV news show “Central FOX,” using the app voting system called “Voto FOX.”  Fans can then contribute their point-of-view about the scores of the games, penalties, and more.
Destino Brasil
By using Parse for Push in their previous apps, the Fox International Channels (FIC) team was able to shift from selling apps for clients to instead concentrating on building apps for their own FIC brands.  This continued momentum is clear with the accomplishments achieved by Destino Brasil.  In its first 4 weeks, the app saw over 150,000 installs, and over 500,000 votes were cast through the Voto FOX system, exemplifying an enthusiastic level of engagement by Destino Brasil’s user base.

Given their prior experience working with Parse, the development team was happy with the results of earlier releases, and the transition to using Parse for Destino Brasil was seamless.

According to Leonardo Rosales, Web Production Executive Director for Fox Latin America Channels, Parse has been the best ongoing solution,

It would have taken a lot of time and resources for us to implement our own solution.  Our developers would have to start from scratch…it would be a pain to put everything together.  Parse is already up and running for a budget price.

As Fox International Channels continues to grow, their objective is to have under ten apps running over the major platforms–browsers, iOS, Android, Windows Phone–and targeting marketing efforts on these focused apps.  Latin America has been a formative testing ground as one of the most developed regions in the sports world, and a region that only continues to progress with the vitality powered by events such as this year’s World Cup and the 2016 Summer Olympics.

For Leonardo’s team, Parse also continues to be the ideal partner through these developments, and their favorite feature, Parse’s reliability, is one that will carry them through it all.

Nancy
June 27, 2014

Parse Developer Community

In 2011, when we launched Parse, we caught the attention of a lot of great mobile developers, eager for a solution like ours. We were quickly faced with questions and feedback that needed to be fielded. We decided to do what many young startups do and built our own tool, a custom Community Forum that was similar to Stack Overflow but tightly integrated with Parse. This has been a labor of love for us, and for a long time, it was precisely the tool that worked well for us.

After 2 years and over 20,000 questions, we’ve decided to try something more scalable and familiar to developers around the world. We will be moving over to several industry standard tools like Stack Overflow and Google Groups to help accommodate the growing community of Parse developers. Whenever we’ve found ourselves in need of help, we’ve gravitated towards using these same tools. We’re excited to continue fostering a vibrant Parse developer community and we hope you’ll take advantage of it when you need help building something awesome. For those of you that have contributed so much time and energy to our community forums in the past, we’d like to enthusiastically say: Thank you!

Plus—don’t forget about the new way to report bugs that we launched earlier this year. This has helped us move from just a couple of folks handling bug reports to a global team of bug squashers, based in London, Dublin, and the US.

We hope you’ll find these new tools helpful, and we invite you to try all of them out on our new Help page.

Héctor Ramos
June 26, 2014

Archives

Categories

RSS Feed Follow us Like us