Search code examples
securitymeteorddp

Meteor allowing me to subscribe from anywhere, security flaw


So I have made a meteor app and I have the autopublish and insecure packages removed, now in order to receive data from my collections I have to subscribe to them in the client. I also have a python program that communicates with my meteor server over ddp using the python-meteor package, in it I simply subscribe to my collections and have complete access to all my data, I can also make Meteor.calls to call functions on the server. This is nice but I can't help but feel like this is a major security hole, anyone can write a client and subscribe to my collections and grab all my data on a whim, if they guess the collection names right.

Is there a way to only let certain clients subscribe to collections and perform server calls?


Solution

  • Yes, you should add security checks to all publishers and methods.

    Here's an example publisher that ensures the user is logged in and is a member of the group before receiving any posts related to the group:

    Meteor.publish('postsForGroup', function(groupId) {
      check(groupId, String);
    
      // make sure the user is a member of the group
      var group = Groups.findOne(groupId);
      if (!_.contains(group.members, this.userId))
        throw new Meteor.Error(403, 'You must be a member of the group!');
    
      return Posts.find({groupId: groupId});
    });
    

    Here's an example method that ensures the user is logged in and an admin of the group before being allowed to change the group's name:

    Meteor.methods({
      'groups.update.name': function(groupId, name) {
        check(groupId, String);
        check(name, String);
    
        // make sure the user is an admin of the group
        var group = Groups.findOne(groupId);
        if (!_.contains(group.admins, this.userId))
          throw new Meteor.Error(403, 'You must be an admin of the group!');
    
        // make sure the name isn't empty
        if (!name.length)
          throw new Meteor.Error(403, 'Name can not be empty!');
    
        return Groups.update(groupId, {$set: {name: name}});
      }
    });
    

    One detail to watch out for: If you are using iron router, be careful not to cause any errors in your publishers. Doing so, will cause waitOn to never return. If you think that throwing an error is possible under normal operation, then I'd recommend return this.ready() instead of throw new Meteor.Error in your publisher.