Rails image upload security
Asked Answered
C

3

1

Currently, I adopt Carrierwave for users to images.

However, I hardly find a solution for image security, i.e. how to set image authorisation for the uploaded images to only let certain user in the same group to view?

After digging Facebook's implementation, I observe that they inject these params (oh,oe, __gda_) to the image url

?oh=924eb34394&oe=55E07&__gda__=1436393492fc8bf91e1aec5

Is there any similar implementation for carrierwave or paperclip?

Thanks

Calves answered 27/4, 2015 at 6:31 Comment(0)
T
1

I worked quite a bit with this (only with Paperclip).

There is one solution that is okay, but it takes a lot of processing.

If you only want to hide your files from being looped through you can hash your Paperclip attachment, see this: https://github.com/thoughtbot/paperclip/wiki/Hashing

If you want to authorize user on every image load you can do like this:

Move your files out of your Public-folder

has_attached_file :image, 
                    styles: { large: '1500x1500>', small: '250x250>'},
                    path: ':rails_root/storage/gallery/image/:style/:filename'

Use Sendfile to view your file

def show
    send_file(object.image.path(:small), filename: object.image_file_name, type: "image/png",disposition: 'inline',x_sendfile: true)    
end

I'm however a bit reluctant to implement this for example an image gallery, since it takes a GET-action + authorization for each image. Using the x-sendfile works with Apache to deliver the images faster.

Ref: http://apidock.com/rails/ActionController/Streaming/send_file

Thalia answered 27/4, 2015 at 6:42 Comment(0)
N
0

I found this great solution for paperclip from https://makandracards.com/makandra/734-deliver-paperclip-attachments-to-authorized-users-only Though a little out of date, this article details everything needed to secure not only the access to attachments, but also how to secure the files themselves. This article describes all of the steps to implement it, including Capistrano deployment!

be sure to use updated routes by changing:

map.resources :notes, :member => { :attachment => :get }

to:

resources :notes, only: [] do
  member do
    get :attachment
  end
end

also I updated the link from:

link_to 'Download attachment', [:attachment, @note]

to:

link_to 'Download Attachment', attachment_note_path( @note.id )

also see Paperclip changing URL/Path for configuring the url.

Np answered 18/10, 2016 at 19:18 Comment(0)
V
0

Carrierwave stores uploads in /public by default, where all content is simply served as static content. If you need to control access to this uploads I'd start by configuring a different storage path

class TestUploader < CarrierWave::Uploader::Base
  def store_dir
    Rails.root.join('uploads', relative_path).to_s
  end

  def serving_path # Use this method to get the serving path of the upload
    File.join '/uploads', relative_path
  end

  private

  def relative_path
    File.join model.class.model_name.plural, model.id.to_s
  end
end

Since CarrierWave relies on public asset serving to serve uploads, you'll have to implement your own file serving method. This is silly example of how to do that with Rails

class Test < ApplicationRecord
  mount_uploader :file, TestUploader
end

Rails.application.routes.draw do
  get '/uploads/:model/:id', to: 'uploads#get'
end

class UploadsController < ApplicationController
  def get
    # ... autorization logic
    model = params.fetch(:model).singularize.camelcase.safe_constantize
    return head 400 unless model.present?
    send_file model.find(params.fetch(:id)).file.path
  end
end
Vermillion answered 11/10, 2017 at 16:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.