Uploads, Storage and Serving Files Safely
Last updated:
Uploads are a common attack route
A file uploaded into a directory the web server will execute is a straightforward route to running arbitrary code. It is one of the two most common ways PHP applications are compromised.
Storing uploads inside the web root is the mistake. Everything else about upload security is secondary to getting that one thing right.
Upload handling
- Store outside the web root, or in object storage
- Validate the content, not the filename extension
- Generate your own filename; never use the uploaded one
- Limit size and type, enforced server-side
- Scan where the files will be shared with others
Serving files
Files that should be private must be served through code that checks permissions, not by a direct URL. A guessable URL is not access control.
- A controller that authenticates, authorises, then streams the file
- No user input used to build the file path
- Correct content type and disposition headers
- Access logged where the documents are sensitive
Where to store them
| Option | Suits |
|---|---|
| Local disk outside web root | Single server, modest volume |
| Object storage | Anything that may scale or needs redundancy |
| Database | Rarely — small files only, and it complicates backups |
Object storage is usually the right answer once you have more than one server or more than a few gigabytes.
Include them in backups
Uploaded files are frequently outside the database backup and therefore outside the backup entirely. A restore that recovers the records and not the documents is a partial restore.
Check specifically that your backup includes the file storage, and test a restore of both together.
Frequently asked questions
How do we validate file types?
Should uploads be scanned?
What about very large files?
Are uploaded files in our backups?
Uploads stored in a public directory?
That is the single most exploitable configuration in a PHP application. Worth checking today.
Related services
What we build for problems like this one