Re: Re: PHP Security

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>> Also, you *SHOULD* force the file to be saved on your server
>> with the correct extension. If a user can upload a JPEG with
>> .php on the end, or worse, with php in the middle of the
>> filename, and then your server puts that file in the web tree or
>> otherwise allows it to be executed, *YOU* (and your server
>> admin) screwed up your security, not PHP.
>
> Trusting the name provided by the client is certainly a bad practice, but
> I wouldn't consider "php" in the middle of a filename to be worse than
> extension manipulation. I'm not sure what gave you that idea, but it's
> just not true.

The original article, in another newsgroup/list, referenced a server seen
by that author, where the SysAdmin had configured the server to use PHP to
parse any file whose name contained 'php'.

Not ending in '.php' ('.php$')

Nor even ending in 'php' ('php$')

But containing 'php' ('.*php.*').

phplogo.jpg, when surfed to, went through PHP.

Real-life problem.

Yes, that's a horribly-configured server.

No, I don't think you'd have that on your server.

But I'd bet at least one reader on this list misunderstands the Apache
Files directive (with and without the ~) badly enough that they've got
this gaping hole on their server.

Now combine that with putting uploaded JPEGs in the web tree, and what
have you got?

My grammar in my post incorrectly put the 'or worse' near 'php in the
middle' when it should have been near 'your server ... allows it to be
executed'

The real culprit, is, of course, the mis-configured server.

But it takes two to tango, here, and throwing the JPEGs in the web tree
should not be done unless you *NEED* to do that, for performance, after
due consideration and a security audit to be *SURE* that the JPEGs cannot
ever possibly get executed as PHP.

>> Under *NO* circumstances should a file uploaded by an
>> untrusted user be put into your web tree. You should *KEEP* it
>> outside the web tree, and use PHP to http://php.net/readfile it
>> when it needs to be displayed. Since you are using PHP's
>> readfile function to *READ* the file, Apache won't have any
>> chance to get fooled into thinking it's supposed to be a PHP file
>> and be parsed by PHP.
>
> This is misleading. It is fine to put uploaded files within document root,
> and in fact many applications may require this. Using readfile() is not
> realistic except for small sites - the performance penalty alone makes
> this a poor approach, since it provides very little value.
>
> That being said, it's true that you should not trust the name provided by
> the client (or anything provided by the client), but this is much
> different than blind paranoia. If this perspective were applied to HTML
> forms, no one could use them.

You don't take raw data from HTML forms and save the field values into
your web tree do you?

You scrub the incoming data from the web form and make sure, as much as
possible for the given field, that it is benign, right?  And you certainly
don't http://php.net/eval that untrusted data from a user, do you?

Then why in the world would you take an untrusted, unscrubbable, binary
file and shove it into your web-tree?!

Can you be 100% certain that <?php /* bad code here */ ?> is not embedded
in the JPEG?  How?  getimagesize() will tell you the JPEG headers are
kosher, but not confirm that the JPEG itself is really really just JPEG
data.

Even viewing it would only, at best, show you an ugly JPEG.

You could egrep for <?php.*?>, and assume that that's not valid in any
JPEG, but it probably actually *IS* valid in at least one real JPEG -- And
if you allow JPEG comments, it would be trivial to have a zillion JPEGs
that would pass any automated validation of JPEG-ness that have PHP code
in the comment.

What's to stop the bad guy from taking a valid JPEG, cramming PHP code
into it, and then surfing to the image directly in such a way that the PHP
code gets executed?

Sure, your server configuration almost for sure doesn't have .jpg files
going through the PHP parser.  But if they can find a way to force that to
happen:
  Altering an .htaccess file somewhere, or forcing one to be uploaded.
  Finding an old cgi-bin setup on the server.
  Getting the CLI PHP to execute the JPG as a script.

It's hard to imagine that last one without them being able to just TYPE a
PHP script, mind you, but some whack 'sudo' setup might do it.  Think
every SysAdmin who uses sudo really understands sudo completely?

Hopefully, none of these things can be done on your server.  If you are
100% certain that none of these could ever possibly occur, then you are
confident that the JPEGs with PHP embedded will only be ugly JPEGs.

But if there is any doubt in your mind that a malicious user could manage
to get the JPEG to be passed through PHP (or Perl or ...) then you've got
a risk there that may not be obvious to the casual
Reader/Sysadmin/Programmer.

Busy servers may have a performance problem with using the readfile
solution -- But that's no excuse to expose that busy server by just
throwing an unscrubbed binary file into the web tree.

I targetted my post at the MAJORITY of users, who are not on busy server,
who *can* easily and trivially use the readfile solution.

If readfile then becomes a bottle-neck the reader can make the decision
what to do about it.

And, perhaps, after a thorough security audit of the risks/benefits
involved, for a busy server with a Security team and auditing and the kind
of budget that goes with that, tossing your JPEGs in the web tree could be
the right solution.  But it's not something I believe you, or I, should
recommend as a best practice for the majority of PHP users.  Do you?

I'd be ecstatic to hear of a performance-viable solution that doesn't
involve putting the binary file into the web tree.  I simply don't
consider that a viable solution from a security standpoint for the
MAJORITY of readers, however.

This is just my opinion, and I know you're way more versed in security
than I.  Perhaps I'm missing some crucial fact here -- Been known to
happen.

But I'd rather have slower JPEGs than risk a bone-headed move in an
.htaccess file turning my server over to the bad guys.  Just me. [shrug]

PS:

Just what percentage of performance loss are looking at, on average, for
PHP/readfile to spew out a JPEG instead of Apache to spew out a JPEG?

Can PHP's readfile really be that much slower than Apache's 'readfile'?

The both have to find the file, fopen it, suck in the data, and spew it out.

You're not, like, throwing in a database connection to lookup the filename
or something like that, are you?  Cuz, yeah, that's gonna slow you down a
whole whole whole lot.  Don't do that. :-)

Or using test data from the old[er] PHP readfile where it was dog-slow? 
That's gonna lose big-time.  But readfile got way more faster at some
point in PHP's history.

Just to be sure I wasn't completely out of line, I ran a crude benchmark
just now.

My admittedly crude tests with "time wget" on:

SunOS 5.8 Generic_117350-12 sun4u sparc SUNW,UltraAX-i2

for a 2 Meg JPEG showed only a 2% difference between the average of five
trials (each) for:

time wget http://example.com/readfile_bench.php
time wget http://example.com/test.jpg

where readfile_bench.php is just:
<?php
  header("Content-type: image/jpeg");
  readfile('/usr/home/rlynch/public_html/id/test.jpg');
?>

Data Analysis:
PHP readfile:
Seconds MB/s
0.23	12.63
0.233	12.2
0.244	12.64
0.223	12.8
0.255	11.04
=== average ===
0.237	12.262

Raw URL:
Seconds MB/s
0.253	10.58
0.226	11.7
0.235	11.32
0.254	10.1
0.246	11.2
=== average ===
0.2428	10.98	2% <---- (0.2428-0.237)/0.2428

For a 2% loss, compared to the risk of a goofball .htaccess setting plus
malicious JPEG upload, I'll stick with readfile for my needs.  YMMV.

-- 
Like Music?
http://l-i-e.com/artists.htm

-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux