Some uploaded files must only be accessible to authorized users. This lesson covers storing attachments securely and preventing users from uploading malicious content.
Important
Work on this lesson in
buildermode.
Learning goals
- You can explain why a file in a publicly served directory is not protected, even when no page links to it.
- You can explain the two common strategies for private attachments — an unguessable path served directly by the web server, and delivery through a controller action that checks authorization — and their trade-offs in server load and in revoking access.
- You can implement attachments that only authorized users may upload and download, e.g. with CarrierWave and a Consul power.
- You can prevent malicious uploads by validating what a file is allowed to be, e.g. by its extension and content type.
- You can explain why uploaded files live outside the deployed release and need to survive deployments, e.g. as a linked directory in Capistrano.
Resources
Read what's new to you, skim what's familiar, skip what you already master. Stop when you can meet the learning goals.
Your agent can also generate an overview, a tutorial or an explanation for anything here, tailored to what you already know. Just ask.
- 📄 Delivering CarrierWave attachments to authorized users only — our card: controller-delivered downloads with an authorization check
- 📄 Preventing users from uploading malicious content — our card: validate extension and content type
- 📄 Self-expiring URLs with Apache — for context, the web-server-side alternative; you don't need to implement it
- 📄
Capistrano:
linked_dirsShow archive.org snapshot — why uploaded files live outside the release and how they survive deployments - 📄
MDN:
Content-DispositionShow archive.org snapshot — forcing a download instead of inline display
Exercises
Add the following feature to MovieDB:
- Actors have a contract document
- Only users with an admin role are allowed to upload or download contract documents
- It should be impossible for an unauthorized user to access a contract document, e.g. by guessing the download URL
Create two implementations of this requirement:
- Contracts are saved to
RAILS_ROOT/public/system, but including a non-guessable secret in their path - Contracts are saved to
RAILS_ROOT/storageand can only be downloaded through a controller action that checks authorization
Discuss the pros and cons of both implementation with your mentor. In particular:
- How much load does each implementation cause on the server?
- Can you withdraw access permissions from someone who used to have them?
Hint
Don't forget to add
storageas a "linked_dir" in your config/deploy.rb Show archive.org snapshot
Posted by Henning Koch to makandra Curriculum (2015-08-20 15:10)