Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Secure way to store files in web server?

Tags:

I want my files to be secure in my web server. Only authenticated users to access those files should be able to access those files. I thought of storing files in database as "Long BLOB" but it supports only upto 2MB of data. The file size may exceed beyond 50MB. is there any other better way to secure the files? please help me.thanks in advance.

like image 410
brainless Avatar asked Jan 05 '11 12:01

brainless


People also ask

What is the best way to store user uploaded files in a website?

Well you have a few options. You can store them as files on the file system, outside the web root. You can store them as binary data in a standard RMDBS like MySQL. You can use a "NoSQL" database like CouchDB or Redis which are specialized in storing documents.

Where does Web server store files?

The best way is to store the file reference in Database. The file itself will be stored in the server filesystem. The complexity of this is making sure there is reference integrity between the database file reference and the existing file in the server filesystem.


2 Answers

Don't store them in a database. Put them in your web directory and secure them using .htaccess.

If you want to authenticate via other means, then store the files in a directory that isn't web-accessible but is readable by the user php runs as.

like image 64
moinudin Avatar answered Oct 14 '22 04:10

moinudin


Discussion

If you opt to keep high value downloadable content files directly on the filesystem, the best thing to do is to keep them outside of the webroot. Then, your application will have to solve the problem of creating URLs (url encoding when necessary) for content (PDF's, Word Docs, Songs, etc..).

Generally, this can be achieved by using a query to retrieve the file path, then using the file path to send content to the user (with header() etc ..) when he or she clicks on an anchor (all of this without the user ever seeing the true, server side file path).

If you do not want user A sharing URLs for high value downloadable content to user B, then your application must somehow make the links exclusively tied to user A. What can be done? Where should I start?

Obviously, you want to make sure user A is logged in during a session before he or she can download a file. What is not so obvious is how to prevent a logged in user B from using a URL sent from user A (to user B) to download A's digital content.

Using $_SESSION to store the logged in user's ID (numerical, or string) and making that part of the eventual query (assuming content is tied to user purchases or something) will prevent a logged in user B from downloading things they have not purchased, but you will still incur the resource hit for processing the SQL empty set for items they have not purchased. This sounds like a good step two.

What about step one? Is there something that can prevent the need to do a query to begin with?

Well, let us see. In HTML forms, one might use a XSRF token in a hidden field to verify that a submitted form actually originated from the web server that receives the POST/GET request. One token is used for the entire form.

Given a page of user specific things to download (anchors), one could embed a single token (the same token, but different per page request) into each anchor's href attribute in the form of a query string parameter and store a copy of this token in $_SESSION.

Now, when a logged in user B attempts to use a logged in user A's shared URL, the whole thing fails because user A and user B have different sessions (or, no session at all), and thus different tokens. In other words, "My link is the same as yours, but different." Anchors would be tied to the session, not just to the page, user, or content.

With that system in place, PHP can determine if a request for content is valid without getting the database involved (by comparing the submitted token to the one in $_SESSION). What is more, a time limit can be established in $_SESSION to limit the duration/lifetime of a valid XSRF token. Just use the time() function and basic math. Sixty minutes might be an ideal token lifetime for an anchor in this situation. Have the user login again if the token for a clicked anchor has expired.

Summary

If you use files on a filesystem and store the paths in the database, make sure you do the following (at minimum), too.

  1. Apply proper file permissions to your content directory (outside of webroot).
  2. Use random names for uploaded files.
  3. Check for duplicate file names before saving a file from an upload.
  4. Only logged in users should be able to download high value content.
  5. Have an effective $_SESSION system that deters session fixation.
  6. Make URLs for high value downloadable content unique per page by using hashed XSRF tokens.
  7. XSRF tokens cover more scenarios when they have a terminal life time.
  8. Make SQL queries for user content based on the logged in user's ID, not the product exclusively.
  9. Filter and validate all user input.
  10. Use prepared statements with SQL queries.
like image 29
Anthony Rutledge Avatar answered Oct 14 '22 04:10

Anthony Rutledge