Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

An eye on security 1

Status
Not open for further replies.

phripley

Programmer
Jun 6, 2007
6
0
0
US
In the apache forum I got help from user feherke on a method to serve large JPEGs as attachments rather than inline.


The script is working reliably. BUT I am concerned about security.

My concern with this tho is that someone might manipulate the request string to get access to files that are not meant to be accessed (?filename=../.passwd or something like that).

I *think* my script limits them to only accessing JPEGs and only accessing the images/press directory. But I thought I would post here to see if anyone else had any security tips...

<?php

/*

*** getimage ***

phr 14 june 2007

the purpose of this script is to serve large jpegs as downloads, while
smaller jpegs are served inline as usual.

it is intended to be used in conjunction with an htaccess rewrite


*/

$pathinfo = pathinfo(__FILE__);
$hostroot = $pathinfo['dirname'];

$filename= $_GET['filename']; // grab the value of the requested file from the url

$ok=file_exists($hostroot . $filename);

// for security reasons we want to allow this script to only function inside certain directories
$safedirectory = "$hostroot/images/press";

if ($ok) { // the file exists
$filepath = pathinfo($hostroot . $filename);
if (strpos($filepath['dirname'],"$safedirectory") === "0" AND ($filepath['extension']=='jpeg' OR $filepath['extension']=='jpg')){
// the file is in the images directory, and is a jpeg
$ok = true;
}
}

if ($ok) { // the file is in the images directory, and is a jpeg
$filesize = filesize($hostroot . $filename);
if ($filesize > 500*1024) { // image is larger than 500KB
header('Content-Disposition: attachment');
header('Content-type: application/octet-stream');
header ("Content-Length: $filesize");
}
else { // image is smaller than 500KB
header('Content-type: image/jpeg');
header ("Content-Length: $filesize");
}
readfile($hostroot . $filename);
return;
}
header('HTTP/1.0 404 Not Found');

?>
<html>
<head>
<title>Error 404</title>
<head>
<body>
<h1>Error 404 - Not Found</h1>
<p>The requested file, "<?php echo $filename; ?>", does not exists.</p>
</body>
</html>
 
You could check for a "/" or any other character that you feel might be used as an exploit and if found, simply explode the string and drop everything except the file name.

Seems the simplest way to me.

Steve Davis

NOTE: This sig does not include any reference to voting, stars, or marking posts as helpful as doing so is cause for membership termination.
 
Hi

Are you sure that works ?
Code:
strpos($filepath['dirname'],"$safedirectory") === "0"
[tt]strpos()[/tt] returns integer or boolean. If you test it against a string with type matching equality operator, should never match. Remove the double quotes ( " ) around the zero.

Feherke.
 
i also do not think it is necessary if you reduce the incoming filename by basename().

more ideally, imo, is to abstract the filenames so that only a uid for each file is known. the path and true file name can then be looked up from a database table or flat file as needs be. of course, the files themselves should be outside the webroot or in a webdirectory with access control set to deny all.
 
Checking a file extension is not at all fool proof
the best way will be to test the file with some GD/PHP function if OK it's a jpg or gif etc...
if not then it could not be an img file
 
<<<
Why do you think phripley will put sensitive data inside the images/ directory and gives it "jpg or gif etc..." extension ?
>>>
He certainly won't, I was/am under the impression that he wants to make sure that the file is what it is supposed to be
 
Hi

Although security is a serious thing I would not slow down the web server with checking the files for their content. The script is restricted to only serve files from a directory - a directory dedicated to store images available for the visitors.

Hmm... And you could also be right, given the amount of details posted here. In thread65-1375304 is abit more :
phripley said:
For a photo gallery-type project I would like to have certain images served as attachments (downloaded) and other served inline as normal.
So content of images/ directory is available for the visitors, just the webmaster wanted to send different HTTP headers for some of images.

Feherke.
 
I'm concerned about this test:

Code:
// for security reasons we want to allow this script to only function inside certain directories
$safedirectory = "$hostroot/images/press";

if ($ok) { // the file exists
  $filepath = pathinfo($hostroot . $filename);
  if (strpos($filepath['dirname'],"$safedirectory") === "0" AND ($filepath['extension']=='jpeg' OR $filepath['extension']=='jpg')){
      // the file is in the images directory, and is a jpeg
      $ok = true;
      }
}

It doesn't have an else block, so whether it fails or succeeds the value of $ok is not changed. You can not, then, assume that the file is in the right directory and is a jpeg like the next block of code does.
 
good catch jet042. Will take all this into consideration and modify accordingly.

Thanks for the support.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top