On Thu, June 23, 2005 7:42 am, Jack Jackson said:
> I cannot see a way to validate or examine Word or Excel files for
> validity (and assume that older word files would validate differently
> from newer ones).

If your PHP does not have the mime_type functions, you could probably use
http://php.net/exec with the "file" utility which does much the same thing
under Un*x-like systems.

"man file" on the command line for more info.

> The PEAR http upload script mentioned twice in the user notes at that
> manual page does not *seem* to validate other than denying certain
> extensions like php, php3, etc. I could be wrong of course.

Does it catch .asp, .cgi, .pl, .htm, .html, .jpg, .png, .gif, .jpeg, .pdf,
and .swf?

Cuz at certain directories on *my* server, those are all PHP scripts!

Well, okay, .pl and .cgi aren't.  Actually, I think I still have a .cgi
somewhere that *is* a PHP script...  It's equally dangerous either way.

Maybe someday they will be on your server, too, once you run into the
zillion IE bugs where the URL counts for more than the Content-type:
header.

It's really Bad Practice to rely on the last N characters of a filename as
some kind of Security Measure to stop a serious attack...

> Also, it seems that directories must be blown wide open (777) to allow
> the script to copy the file over from /tmp. My ISP won't allow
> directories to be set to 777 under public_html/ -- but we need to access
> the files via web browser which is the whole point.

Well, requring 777 just plain sucks...

You *should* have a directory writable by the PHP user/group as the
minimum requirement.

If PEAR really and truly requires 777, then that feature of PEAR sucks,
and you shouldn't use it.  Sorry, PEAR guys.  Gotta call 'em as I see 'em.

And if the best it can do is outlaw .php .php3 ..., then that ain't much
either.  I'd rather code it myself than have that weak of a safety.

> So my questions:
> 1. How do you validate Word and Excel files before upload?

You don't.

Any validation done before upload is done on the client, and is therefore
something that can be easily bypassed by the savvy user.

It might be useful as a User-Interface feature to catch obvious stupid
mistakes by honest folk...

But it's USELESS as a Security Measure to stop Bad Guys.

Oh yeah:

You may need to use move_uploaded_file to move the files to a staging area
before you use exec/file on them...

At least, under *MY* webhost's setup, I can't directly read PHP uploaded
files from /tmp, even though PHP can move_uploaded_file() them... That may
have been changed/fixed, but it's a possible configuration issue.

So, use move_uploaded_file to let PHP do its checks, but put stuff in a
staging area that the PHP user can read/write, and is *NOT* in the
web-tree.

Then, do all of YOUR checks.  getimagesize, exec("/usr/bin/file $file"...)
etc.

If that all passes, move the file (again) to its final destination, which
should *still* be out-side the web tree on most shared servers.

Write a PHP script that only allows files already listed in your database
to be served up, and which readfile's the data from outside the webtree to
spew it out.

*IF* you are on a dedicated server, or *IF* your webhost has a unique
UID/GID for you to have directories that no *OTHER* user on that webhost
can write to your PHP-writable directories/files, *then* it is
probably/maybe just as safe to put stuff in your webtree as to readfile it
from outside the web tree...

Even then, I'd only do the direct to webtree if performance was a major
issue.  It just doesn't make sense to me to let untrusted users put stuff
in the webtree where they might manage to trick the server into executing
it as Perl, PHP, JSP, ASP, or [deity] knows what code to do Evil things.

It's gonna be a lot tougher for them to fool PHP's readfile into executing
code.  Hell, if they can do that, they already own your server.

> 2. How can I make a passthrough from a file above public_html to one
> below it so that people can surf in with a browser and download files
> which have been uploaded by the script?

There's an easy one. :-)

Put the files *OUTSIDE* your webtree.

Then write a PHP script that takes an ID of a valid uploaded file that
your previously stored in your database, looks up the path to that file,
and use http://php.net/readfile on it.

You were real close with passthrough which is http://php.net/passthru
which is kind of the same, only not.

You'd only put files in the webtree if PHP readfile proved too slow, *AND*
you were sure no user on the box could ever manage to infiltrate a
damaging file into the webtree...

That second one is a pretty Tall Order...

I can see somebody justifying it, but, honestly, if the overhead of
readfile is that big of a deal, then maybe you're living too close to the
edge on performance in the first place, and it's time to buy more/better
hardware anyway.

So, in MY opinion, you should NEVER put uploaded files from untrusted
users in the webtree.

Sure, if it's the site's "admin" user or some trusted user who you have a
Reasonable Expectation that they simply wouldn't upload Bad Stuff, putting
in the webtree isn't quite as bad...

But you have to consider the ultimate source of the content.

Are they just uploading what somebody else sends them for a headshot?

You really think there isn't somebody out there that couldn't generate a
reasonable-looking headshot that, if passed through PHP, would do Bad
Things on your server?

Jeez, I think even *I* could manage that.  Throw some PHP code into the
Comments section.

If they can manage to get that file to end up in a directory of PHP
scripts that generate GD images, and those scripts end in .gif to fool the
broken IE browsers as some of mine do, it could be Game Over.

Maybe this can't happen on your server today, but can you guarantee you'll
NEVER have sombody playing around with GD and using ForceType to solve the
IE bugs?

Put it outside the webtree and use readfile, and you can't go wrong.

-- 
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

Reply via email to