Alain Williams wrote:
> This has just appeared:
> 
>       http://www.theregister.co.uk/2007/01/11/php_apps_security/

There are some concrete suggestions in the article that we addressed a
while ago.  Things like:

  "I'd like to see new defaults that limit include() and require() to
   only allow local files, thereby avoiding remote file injection."

That's the default in PHP 5.2.0 which was released over 2 months ago now.

  "It would be nice to have a global way for a script to ignore all
   variables in the URL, avoiding unexpected variable manipulation and
   XSS forgeries."

We can't really make that the default (which isn't suggested) since that
would break a lot of stuff, but is has been possible to do this for
years by simply removing "G" from the variables_order setting.

  "Maybe there's even a way to force users to filter input and escape
   output every time, helping to avoid SQL injection and all sorts of
   other common problems. That last one would go a long way."

The filter extension has been available for quite a while now in pecl
and is bundled with PHP 5.2 and it does exactly this.

I won't disagree that we can and should do more to help people write
safer apps, but we have to balance that with the ease of use that
brought people to PHP in the first place along with the massive amount
of existing code out there.  It is an interesting balancing act.

Another thing to keep in mind is that there are two very distinct
security issues here.  Remote vs. Local issues.  Just about every
reported security problem against PHP itself has been of the Local
variety.  That means that it is a flaw in our various attempts to
separate users that share the same server in a shared hosting
environment.  I wrote about this back in 2004 in this note related to
the PHPBB issues at the time:

  http://www.php.net/security-note.php

Like I said there, when you share a server with someone else, you are
never going to achieve 100% security against those other local users,
especially if the ISP is running everyone on the same Apache instance
with the same user id, etc.  But even with jails/chroot there have been
some interesting ways over the years to defeat those, and I don't doubt
there will be more.  Same goes for local PHP issues.  It is very hard to
protect the user from himself without completely crippling the language
and the various attempts we have made over the years like safe_mode and
open_basedir can never be fully secure.  Something like open_basedir is
however useful as one layer in a layered security model.  For example,
you can do an initial layer of user input filtering using something like
mod_security, then further filter using the filter extension and finally
use open_basedir to define a restricted set of directories that an
application should be able to open files from.  Any one of those 3
layers may not be 100% secure by themselves, but the chances are pretty
good that in combination it would be quite hard for something nasty to
get through since the holes in each would have to line up perfectly.

An example would be naiive code like this:

  readfile("/some/path/".$_GET['filename']);

Assuming the developer didn't think about input filtering at all,
someone could simply put: ?filename=../../etc/passwd
in the URL and they would see the local /etc/passwd file from the
server.  Even with shadow passwords on most systems today, it is a bad
idea to allow remote users to read any file on your server.

In this case you could have a mod_security rule to disallow ../.. style
patterns in URLs.  But if someone found a way to still sneak that
pattern through, perhaps because of a bug in mod_security related to
weird and wonderful character set tricks, if the application had a
well-defined open_basedir setting the readfile() call would fail trying
to read anything from /etc

A second example:

  <a href="/download.php?filename=<?php echo
$_GET['filename']?>">download</a>

Again, a very common type of mistake.  Without any sort of input
filtering the remote user can do something like:

  ?filename=/etc/passwd"onmouseover="alert(document.cookie)

Here the bad guy is trying to do 2 attacks at once.  It is trying to
trick the download.php script into downloading /etc/passwd and it is
doing a very common XSS attack.  Going through our layers we might have
a mod_security rule that tries to strip out tags, but in this case since
there are no tags and we are simply adding an attribute to an existing
tag, it might slip through.  Next, ext/filter kicks in with a default
filter of "special_chars" for example and changes " to &quot; and the
XSS is defeated and finally open_basedir stops the /etc/passwd access.
This would all be without changing a single line of code in the
obviously badly written application.  Just a couple of configuration
options in Apache and PHP.

Of course, such default filtering and strict open_basedir settings might
break the app if it is expecting unfiltered input somewhere in it or it
is expecting access to a dir you haven't added to your open_basedir
list, but it becomes pretty easy to identify the few places in an app
where you need to loosen things a bit simply by starting off very strict
and seeing where things break.

I hope this explains some of our current thinking towards PHP security.
   I really don't think things are as bad as people make them out to be,
but it is all about perception, so if they think it is bad, it is bad
and we need to do a better job documenting things like the filter
extension and how to apply a layered security model in PHP.

-Rasmus

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to