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