Welcome Guest, Not a member yet? Register   Sign In
Question about file uploads
#1

[eluser]thurting[/eluser]
Hello,

I am working on a project that requires users to upload an image file via a form and have some questions. I would like to store these images securely so users cannot view them. I'm thinking about saving them above the web root, but I would also like to be able to view them through a web based admin area I am setting up. Is there any trickery (Apache or PHP based) that would allow me to have the files stored on the web root of my site, but only be available to users with admin credentials (maybe set up a script that does auth, then spits out the files with proper headers - e.g. web root at /htdocs and http://mysite.com/images/view/blah.jpg will do auth and read a file at /private/images/blah.jpg)? If not, I'm thinking the best course of action is simply to store the images with random names so it would be difficult for a user without access to the db or fs to access them.

Thanks.
#2

[eluser]xpix[/eluser]
make the folder name random
#3

[eluser]Rick Jolly[/eluser]
Yea, I'd store the images above the web root. Then have the controller stream the image. You could do that directly in the controller, or have any view call the controller from an image tag.
Code:
<img src="image_controller/download/file_name">
Here is an untested download helper function modified from another framework. It won't force download like CI's helper, but show the image in the browser window.
Code:
public function download($filepath)
{
if (is_file($filepath))
{
  // Get the real path
  $filepath = str_replace('\\', '/', realpath($filepath));

  // Get extension
  $extension = pathinfo($filepath, PATHINFO_EXTENSION);

  // Set filesize
  $filesize = filesize($filepath);

  // Load the mime types
  @include(APPPATH.'config/mimes'.EXT);
            
  // Set a default mime if we can't find it
  if ( ! isset($mimes[$extension]))
  {
   $mime = 'application/octet-stream';
  }
  else
  {
   $mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
  }

  // Generate the server headers
  header('Content-Type: ' . $mime);
  header('Content-length: ' . $filesize);
  readfile($filepath);
}
}
#4

[eluser]thurting[/eluser]
Thanks for the replies. xpix, this is obviously the easiest solution, but I am worried about security. Rick, in terms of high security, that's what I was thinking. Thanks for the example. I had forgotten about that handy mime lookup table. In this case, I think I'm going to go with the more secure option. Anyone else have another solution? Thanks again.
#5

[eluser]thurting[/eluser]
Hi Rick,

I haven't played with your code, but I came back to ctrl+c as a starting point, and noticed what looks to be a pretty severe vulnerability. Because $filepath is taken from the URL, it can be manipulated by the user; e.g. ../../../etc/passwd. Now if ../../../etc/passwd existed on your fs, the user would be able to access that file given your implementation. I know you said this was untested, but if you have it deployed, you should patch it immediately.
#6

[eluser]Rick Jolly[/eluser]
That's worth mentioning. The example was a starting point and we all know to validate any inputs. I didn't include any controller code, but in the controller you'd validate that the file name is actually a file and not a path. Only then you'd append the file name to the path of your choice and call the download function.

Of course, you wouldn't actually be able to pass a "/" in the img tag without it being treated as another parameter.




Theme © iAndrew 2016 - Forum software by © MyBB