Meteor Security Permissions on Uploaded Images

Viewed 70

I'm creating a Meteor chat app. I want users to be able to send images to each other, but users not in the group/conversation shouldn't be able to see the image. My first thought was to give an image a unique ID and store the image with this ID in a public folder in my or a 3rd party server.

For example, if the user uploads an image called "name.jpg", it could be stored in Amazon S3 as A3eedAcRCqCa32451.jpg. That way, anyone with the ID can access the image, but the only people with access to the ID would be those in the group chat, since I can ensure secure access using Meteor's publish and subscribe rules. However, this doesn't feel safe to me. Is my intuition right?

If yes, how else would I do it? I searched online and on StackOverflow and couldn't find another simple way to achieve this.

2 Answers

You usually have two things you can do when considering granting access to resources:

  1. Authentication and access control
  2. Indirect object references with sufficient entropy to make brute force attacks hopeless.

Point 1 is more or less obvious. Point 2 is actually what you have already on your mind. To reason about the security of the second approach let's consider following:

  • The entropy of A3eedAcRCqCa32451.jpg is about 80 bits.
  • The count of the domain is 2^80 = 1208925819614629174706176.
  • An attacker can try to guess the secret.
  • Let's say, he can make 10 guesses a second and on average he will guess after |domain|/2 tries.
  • It would take the attacker ~2 mln years to guess.

Now the domain of 80 bits is a bit small from the security perspective. Make it 128 bits by using type 4 UUIDs. I believe you see where this is going.

It depends on the security level you want...
A more secure solution would be to store in a collection the imageId and userId of people that can access the image. When someone wants to access it, you just have to check if he's in the list of allowed users.

Then as you said you can use a 3rd party storage (personally I'm using ostrio:files with Dropbox integration, the docs about it aren't up to date but I made a pull request which was accepted on the dev branch with a working example, you can take a look at it here.)

The nice thing with ostrio:files is that it offers built-in functions like onAfterUpload or interceptDownload in which you can store data about access for the first and check if access is allowed for the second.

Related