No matter if it’s a crafty user or not, server-side authorization is always still your best defense. We don’t allow any user to modify their profile from the client, which is our first defense. But even if a user can sniff out the appropriate Method or Publication, we have our authorization guards on the server that prevent any payload going out unless they have the right privileges.
In our app, we have a notion of Spaces, where users can be part of a collaborative group of others. When a user sets up multiple Spaces with others, they can switch between them. Since we don’t want users trying to “guess” a Space they’re not part of, here’s an example Method we use to keep them in line:
spaceSwitch: function(id) {
if (!this.userId) { // authentication check
return; // if not logged in, just bail immediately
}
check(id, String); // assertion. this is the id of the space they're switching to and it better be a String
var user = Meteor.user();
if(user.allSpaces.indexOf(id) === -1){ // authorization check: if the id they're switching to isn't in their array of existing spaces...
return; // then bugger off
}
Meteor.users.update({_id: this.userId}, {$set: {'space': id, 'profile.space': id}});
return 'switched';
}
One note on the publish function above: instead of returning all documents with the isSubscribed
field, if you were trying to restrict access to the Publication based on that property, one modification could be this:
Meteor.publish('userExtraFields', () => {
var user = Meteor.users.findOne({_id: this.userId});
if (user && user.isSubscribed) { // don't bother sending documents to the client unless this is true
return Meteor.users.find(
{ _id },
{
fields: {
isSubscribed: 1,
key: 1,
stripe: 1,
version: 1,
},
},
);
}
return false;
});
I’m assuming that function is written to serve that app’s use-case, but just wanted to point this out for @robinhunter27 as an example to restrict access at the Method or Publication level.