How to authorize access to images uploaded to S3 by users?

66 Views Asked by At

Imagine the app with the ability to upload files by users. Only the author (the person who uploaded this file) and the author's friends should be able to see this uploaded file.

I am using "carrierwave" gem to handle uploading files. It gives me the ability to get a file URL.

# models/user.rb
class User
  mount_uploader :secret_file, SecretFileUploader
end

# uploaders/secret_file_uploader.rb
class SecretFileUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
    
  def extension_white_list
    %w[txt]
  end
       
  def store_dir
    "secret_files"
  end
end
    
    
u = User.last.secret_file.url # => "https://bucket-name.s3.amazonaws.com/secret_files/secret_file_name.txt"

If someone stoles this S3 URL, then they can access this file at any time.

How to handle this situation? How to authorize only the author and the author's friends to open this file?

1

There are 1 best solutions below

0
Milind On

To ensure uploaded content is only visible to the users and its associated friends, you need to make sure few things -

  1. You need to associate every uploaded content, like - user.images showing only user images.
  2. You have to create presigned urls - they are like single use urls which can be used only once and have an expiration to avoid misuse.
##in user.rb
has_many :images, :dependent => :destroy

##in image.rb
belongs_to :user
mount_uploader :image, ImageUploader
  validates_presence_of :image
  ##to validate uploads - https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Validate-uploads-with-Active-Record
  validates_integrity_of :image
  validates_processing_of :image

image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base

  #Override the directory where uploaded files will be stored.
  #This is a sensible default for uploaders that are meant to be mounted:
  #this way you ensure the files are uploaded to each users folders
  def store_dir
      "inputs/images/#{model.user_id}/#{model.id}"
  end

 ##in carrierwave.rb, you configure presigned urls using fog gem.
 CarrierWave.configure do |config|
  config.fog_credentials = {
    :provider               => 'AWS',
    :aws_access_key_id      => "xxxxxxxxxxxxxx",
    :aws_secret_access_key  => "xxxxxxxxxxxxxx",
    :region                 => "any valid aws region"
  }
  
  #this is where you configure presigned urls
  config.fog_directory  = "dev-bucket"
  config.fog_attributes = {
    expires: 10.minutes.from_now.httpdate,
    'Cache-Control': 'max-age=315576000',
    server_side_encryption: 'aws:kms'
  }
  #default is 60 seconds
  config.fog_authenticated_url_expiration = 60
end

once done, you can use something in your views like - @user.images to view all images of a user. you can extend this with any logic to show all list of images to the users friends.

Try it out and let me know if it helps.

To know more about how to avoid unwanted access to your files in AWS S3, CHECK THIS LINK