The data browser is built for Chrome, Firefox, Safari, and IE9 and above. Please upgrade your browser, or download Google Chrome to get the best experience.
Back to Questions

Object Security in Parse using the JavaScript API - Tying Users to the objects that are saved

1 vote     1 answer     1.12k views     

1

Duplicating my question from stackoverflow here: http://stackoverflow.com/questions/13277258/object-security-in-parse-using-the-javascript-api-tying-users-to-the-objects-t

In managing entities in Parse there are a lot of objects that I need to tie to the current logged in user.

My concerns are:

  1. There is no backend code ensuring that the User being passed in is the current logged in user.
  2. Users could assign any newly created objects to other users.

They have <a href="http://parseplatform.github.com/Todo/">this example TODO app</a> which in <a href="https://parse.com/tutorials/todo-app-with-javascript">the documentation</a> shows no Cloud Code in place to ensure that the User that the Todo is assigned to is the currently logged in user.

Now that I look through <a href="http://parseplatform.github.com/Todo/js/todos.js">the code</a> I'm starting to think that whenever an object is saved it gets tied to the user. Can anyone explain why this application works and how it is associating the Todos with the User?

UPDATE: Nevermind, I found the place in their code where they specify the user to save for the Todo. My question is, what's stopping a user from writing code that saves the todo with someone else's user id?

this.todos.create({
        content: this.input.val(),
        order:   this.todos.nextOrder(),
        done:    false,
        user:    Parse.User.current(),
        ACL:     new Parse.ACL(Parse.User.current())
      });

UPDATE #2: If the User object has an ACL set to only allows users to be able to read User objects they own, then they wouldn't be able to query to get another user object to pass up. However, there are two other possible problems:

  1. Is it possible for them to pass the objectId of the user instead of the entire User object even if the user field on the Todos table requires a _User?
  2. I believe they could also create a new user object and assign it to that... I'm trying to think of a scenario where this would be an issue, but I can't right now.

If anyone can confirm or provide solutions to either of those that would be helpful. Going to try to test #1 right now.

UPDATE #3 -- After some testing:

  1. If the user field on the Todos table requires a _User object, it will not take the objectId as a string.
  2. The they can however create a new user object and set the objectId there to get around this.

    var user = new Parse.User();      // Create user object
    user.id = "cqmEuj1Bzf";           // Assign user id
    
    // Create and save Todo
    var td = new Todo();              
    td.set("name", "Some ting todo");
    td.set("user", user);
    td.save();
    

This right here is exactly what I was worried about. I was able to successfully save a Todo to another user's account--as long as I know their user_id (objectId). With enough users they can likely guess at least one to randomly screw up someone's account.

So what now?

1 Answer

3

You can use Cloud Code to ensure that the objectId corresponds to the current user making this request. In fact, our sample application, Anypic, does this check on the "Photo" and "Activity" class.

From Anypic's Cloud Code:

Parse.Cloud.beforeSave('Activity', function(request, response) {
  var currentUser = Parse.User.current(); 
  var objectUser = request.object.get('fromUser');

  if(!currentUser || !objectUser) {
    response.error('An Activity should have a valid fromUser.');
  } else if (currentUser.id === objectUser.id) {
    response.success();
  } else {
    response.error('Cannot set fromUser on Activity to a user other than the current user.');
  }
});

Parse.Cloud.beforeSave('Photo', function(request, response) {
  var currentUser = Parse.User.current(); 
  var objectUser = request.object.get('user');

  if(!currentUser || !objectUser) {
    response.error('A Photo should have a valid user.');
  } else if (currentUser.id === objectUser.id) {
    response.success();
  } else {
    response.error('Cannot set user on Photo to a user other than the current user.');
  }
});