Where to allow Uploads

My website allows registered users to upload a photo of themselves.

I feel my upload script is rock-solid as far as making sure an uploaded file is safe.

However, from a System Admin standpoint, where should I stick the uploaded photos?

Currently, I have an “uploads” inside the Web Root.

How dangerous is that?

Would it be better to keep it there, or place the “uploads” folder outside of the Web Root?

(I will be setting up a Virtual Private Server (VPS) with GoDaddy that is on a Linux server and uses cPanel.)

Sincerely,

Debbie

Upload locations inside the web root are very common so unless there’s a specific reason you need to hide the path then general images would be fine there. It’s also worth noting that profile avatar URL’s on this forum don’t give away the image location (you can still save the image though!).

The only time I’d store data above the root is if the files were somehow sensitive, such as documents that require payment (eg so you can’t access them via a URL)

A lot of people say you should store images above the web-root. Especially if they were uploaded by users.

Interesting!

I was able to to find this…


      <a class="postuseravatar" href="member.php?85867-bluedreamer" title="bluedreamer is online now">
        <img src="image.php?u=85867&amp;dateline=1386442668" alt="bluedreamer's Avatar" title="bluedreamer's Avatar" />
      </a>

So can you explain how that works to hide the avatar’s actual location?

I guess this is the key part here…


img src="image.php?u=85867&amp;dateline=1386442668"

I think some of the fear of leaving uploaded photos in the web root, is that a hacker could upload an “image” that is executable in some way, and if it is left in the web root, then a hacker could upload a nefarious image, and then execute it.

Sincerely,

Debbie

FWIW, here is some sample code used to display “Last 10 Visitors” in a member’s profile…


<li>
	<a href='/account/profile/Sam-I-Am/about-me'>
		Sam-I-Am
		<img id='onlineStatus' src='/images/Light_Gray_10.png' width='8' alt='Member Offline' /><br />
		<img src='/uploads/a73dc554b0f812fec6553652750f48c20f6cee1b.gif' width='60' alt='Thumbnail of Sam-I-Am' title='Sams Spiral GIF' />
	</a>
</li>

The way I have it now, you can clearly see where the Online Indicator and the Visitor’s Thumbnail are located on the file system…

Sincerely,

Debbie

Yes, that’s most likely where the image.php script pulls in the image behind the scenes and applies the profile link dynamically without giving the image location away.

I’m no PHP guru but a quick search found http://foundationphp.com/tutorials/image_proxy.php - looks like one way to do it but there are probably others!

Possibly if there’s a vulnerability in a script, but it’s worth remembering hackers can get in in many other ways, the clever ones will probably be able to access folders above the root as well.

My 2c has always been upload the file, store it in a non-accessible temp path and keep the backing copy in the database. Cache out to disk from the DB on a separate, non-server-side-enabled host, to avoid that overhead of serving files out the db. This is more secure (no real hole for someone to upload and execute a malicious file) and more easily transportable (just a database backup, not a database backup + files).

Sure there are other ways to get in but having the ability to upload files to a predictable location makes a lot of very dangerous attacks interesting or possible.

Not sure that I followed what you were saying…

Can you be more specific?

“Backing” copy???

Again, I don’t know what you mean…

Sincerely,

Debbie

Typically you need to store a file somewhere temporarily while things are processed – the place to do that is a non-web accessible temporary path of some sort. More power if you can keep it in memory and never touch the disk.

Backing copy means the master copy of the file, the one you backup, the one you can recreate any artifacts from if need be.

The reason I suggest caching the files out on disk (or a real CDN) is that serving files out of the database can be a brutal performance issue, even at small scales so it is best to architect around that.

How hard would it be for a mere mortal like to to code such a solution? :-/

It sounds really, really complicated and like it would be over my head…

If I understand what you are saying, when a user uploads a profile picture, I would store it in the database, and then when some other user visits said member’s profile, my code would retrieve the profile picture from the database and write it to another server - or at least a location outside of the Web Root - to some “file server caching location”.

That way, there would only be a database hit once, and any further profile picture requests for said member would be fulfilled by the “file server caching location” - which is some secure, not easily hacked area - instead of beating up my poor database.

Is that the gist of it?

Sincerely,

Debbie

This isn’t really particularly difficult to build – you just separate the ingest and egress parts of the upload and image serving process. You did pick up the gist of it.

Are you an attorney?! :stuck_out_tongue:

Okay, maybe I can give that a try in v3.0

Thanks,

Debbie