Safe Methods in Meteor

2019-09-14 15:42发布

I'm working on a messaging app using Meteor. I disabled any insert/update/remove called from the client for security reasons. The only way to insert messages now is by using Methods.

Meteor.methods({
  sendMessage: function (text) {
    Messages.insert({ userId: Meteor.userId(), roomId: Rooms.findOne()._id, name: Meteor.users.find(Meteor.userId()).fetch()[0].profile.name , message: text });
  }
});

This approach asks only for the content of the message, so there's no way for a user to call the method using other name or try to send the same message to other Chat Rooms.

I'm a beginner using Meteor so I wonder, wouldn't the real method (not the Stub) which is run on the server get different values from userId and roomId? Rooms.findOne()._id on the server could be any random room document on the db, as well as userId any user.

If this is the case I would have to include extra parameters on the function which would make it much less secure.

I'm probably not understanding about Methods here.

1条回答
甜甜的少女心
2楼-- · 2019-09-14 16:24

You are on the right track. Using Rooms.findOne() certainly doesn't make sense on the server, and frankly isn't that good on the client either (if you ever publish more that one room this will break). You need to pass both the message and the room id to your method. The method should validate that the insert makes sense. For example, is this user currently in the room. Assuming that's tracked in room.members, sendMessage could be implemented as follows:

Meteor.methods({
  sendMessage: function(message, roomId) {
    check(message, String);
    check(roomId, String);

    if (!this.user)
      throw new Meteor.Error(401, 'You must be logged in.');

    if (_.isEmpty(message))
      throw new Meteor.Error(403, 'Message must not be empty.');

    var room = Rooms.findOne(roomId);

    if (!room)
      throw new Meteor.Error(404, 'Room not found.');

    if (!_.contains(room.members, this.userId))
      throw new Meteor.Error(403, 'You are not in the room.');

    var name = Meteor.user().profile.name;

    return Messages.insert({
      userId: this.userId,
      roomId: roomId,
      name: name,
      message: message
    });
  }
});

Not all of these checks may be necessary, but this example should give you an idea of the rich set of validations that a method can provide.

查看更多
登录 后发表回答