Restrict system files access to the public - ruby-on-rails

Ruby on Rails 3.2
My application has images stored in:
http://name.name.com/system/images/imgs/xxx/xxx/xxx/thumb/xxx.jpg?xxxxxxxxx
I noticed that you can get access to the files when not logged in. I tried doing a before_filter in my controller but when I look at the log there is no query, and it is not using the controller.
How do you restrict access to system files to only users that are on my website and logged in? Thank you,

You need to remove the files from the $RAILS_ROOT/public folder and move them somewhere else, e.g. $SHARED_FOLDER/uploads/.
Then create routes that point to a controller:
class FilesController
def show
# first check credentials
path = ... # use params to look up the path, but be careful to check the
# validity!
# It's probably best to have an index that contains valid files
# and to only return those. Otherwise an attacker might be able
# to compromise your server and your data.
send_file path
end
end

Related

Ruby on Rails file authorization under RAILS_ROOT/public

I am looking for a way of running a type of check_access to my files located under my public folder. I heard about RAILS_ROOT/private. I believe this directory provides my demands.
But I don't have deep information about it. The core idea of mine is serving files to only use which has the ability to view/download the files. Such as a posted pictures, I don't want them to be public. Currently, all the people who have knowledge of the URL pointing to the correct directory can access all files.
PS: The files under /public dir are uploaded via carrierwave gem.
Thanks.
If you need access control for your files you don't want to serve them from your public folder. Your public folder is server either by ActionDispatch::StaticFile or directly by your web server - neither of which provide the kind of access controll you want.
Instead you would create a controller which serves up the files:
class FilesController < ActionController::Metal
before_action :authenticate! # you need to implement this
before_action :authorize! # you need to implement this
# GET /files/:filename
def show
path = Rails.root.join(
'uploads', # can be any directory you want really
# avoids a malicous user being able to use for example '../../secret/password'
ActiveStorage::Filename.new(params[:file_name]).sanitized
)
if File.exist?(path)
send_file path
else
head :not_found
end
end
end
You can define the permissions in your database and then you can add a check before displaying the url of a file to the users. You shouldn't keep the files in public folder if you want them to be restricted.

How to list directory folders in rails

Hi I am newbie in rails and wanted to know any way to list folders and files for a url say public . So example user types example.com/public he gets all folders and files listed as we do in php if we start a wamp server . I need this so I can create files and have their url shared to public i.e. simply send url link online like example.com/public/test.pdf . Currently I am getting page with no routes defined .enter image description here
Thanks.
Create a controller to serve the file using a route parameter, ex.
get '/public/:filename', to: 'file#serve'
Then use the send_file method in your controller.
class FileController < ApplicationController
def serve
# For authorization:
#authorize!
# For authentication: (a way or another)
#redirect_to :access_denied unless user_signed_in?
send_file "/www/yourapp/var/files/#{params[:filename]}"
end
end
This way the file can be anywhere within your app, or even on a Cloud storage. It also gives you the ability to use authentication or authorization to check if the user has access.
Please note that this code is very simple, but there are much more options like Fog gem for Cloud storage and everything else.
See https://apidock.com/rails/ActionController/Streaming/send_file for more information.

Allow users to download a file

I've read through a number of StackOverflow threads and tutorials, and I haven't found a good, simple explanation for how to allow a user to download a file from your site.
All I want to do is add a link to one of my views which downloads a file when clicked.
I'd like to understand:
Where do I store the downloadable file in my file system? public?
Is there anything special about linking to the file in your view, or it's just a link_to?
What needs to happen in routes? It's just a get for that controller#action?
What needs to happen in the controller? In rails documentation I've read that you need to "be careful to sanitize the path parameter if it is coming from a web page," but I'm not sure exactly what that means.
Thanks!
In simple scenario, you don't need controller to download file. Just save file to public folder. Public folder is default folder for static resources there are stored compiled js, css, images files, robot.txt and so on.
If you have file monthly-report.doc. Put it to public/reports/monthly-report.doc.
In view link_to 'Donwload Report', '/reports/monthly-report.doc'
There are basically two cases:
1. The file is public and should be downloadable by anyone.
Place it in the /public directory. Remember that this is the web root - so if you have a file that lives at /public/foo/bar.baz you would link to the file with <%= link_to 'A file', '/foo/bar.baz' %>.
No routes or controllers are need since we are just serving a static file from the servers public directory.
2. The file needs access control
In this example we are dynamically servering files stored in /downloads.
# routes.rb
resources :downloads, only: [:show]
class DownloadsController < ApplicationController
# do your authentication logic here
# GET /downloads/:id
# #example
# GET /downloads/foo.bar would download a file stored at
# /downloads/foo.bar
# #raise [ActiveRecord::RecordNotFound] if the file does not exist.
# This causes a 404 page to be rendered.
def show
fn = Rails.root.join('downloads', params[:id])
raise ActiveRecord::RecordNotFound and return unless file.exists?(fn)
send_file(fn)
end
end
By using Rails to serve the download we can apply whatever access control rules we want.
The link_to is the same as any other link.
If you want to store it in public then do this in whatever controller action you want.
send_file File.join(Rails.root, 'public', 'file.extension')
You could create a downloads controller and specify that in the index then simply link_to 'Download', download_index_path or such.
If you're trying to send a file name that a user inputs, you have to sanitize it. If it's "hard coded" like the above example, then you're fine.

how to have a browse file field that uploads only path

I have a field on my model Site called file_link. In the edit form, I want there to be a field for file_link with a Browse button next to the field, which pulls up a file browser on their local computer. I want them to be able to select a file, then have rails save the users local Path to the file, not the actual file.
For Example: file_link should save the path: N:\Projects\excelfile.xlsx
How can this be achieved?
when you visit a website, there is no way for the website to access your filesystem unless they somehow hack you. This isn't specific to Rails sites ... it's a fundemental security precaution of the internet. If you want to access your users' filesystem, you may be able able to do it with Javascript after gettin their permission, but might not be be easy. See Can javascript access a filesystem?
However, if you are building this app for localhost use only, you can use Ruby to manipulate/show the filesystem all you won't. But it's going to be limited to the filesystem running the Ruby program.
There few gems able to help you with that. And one of them is called Carriervawe.
Gem LINK
u = Site.new
u.file_link = params[:file] # Assign a file like this, or
# like this
File.open('somewhere') do |f|
u.file_link = f
end
u.save!
u.file_link.url # => '/url/to/file.png'
u.file_link.current_path # => 'path/to/file.png'
u.file_link_identifier # => 'file.png'

Rails file location and access

My root is site/home/ubuntu/workspace/
Is it possible to access file (from browser by HTTP request) located inside workspace/ without configuring routes and controllers?
Does the question on 1) depend on file extension?
you can access path to your file like this:
File.expand_path("somestuff.rb", "~/workspace")
for me this code produces path as follows:
"/home/foodie/workspace/somestuff.rb"
I have this structure:
# /home/username/Workspace/rails_project/app/controllers/application_controller.rb
require "#{Rails.root}/../test.rb
And
# /home/username/Workspace/test.rb
# Some ruby code
As you can see, test.rbfile is outside RubyOnRails Project.
For security reason, you can not access a file outside project rails from URL without defining a route. What you can do, is point a route to controller that, based on file name provided at url, require a file outside rails project.
# /home/username/Workspace/rails_project/config/routes.rb
get '/get_file/:file_name', to: 'files#show'
# /home/username/Workspace/rails_project/app/controllers/files_controller.rb
class FilesController < ApplicationController
def show
document = params[:file_name]
send_data "#{Rails.root}/../#{document}, filename: document
end
end
For more info, see:
http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_data
Without configuring routes and controllers, client can only access files in the public/ directory (it doesn't matter what the extension is). Bare in mind this: when your Rails app is run by webserver, its webroot will be the public directory, consequently to access public/file.ext you request should be webroot/file.ext

Resources