Dear Developers of PHP:
I have a proposal that I hope you'll like & that I think will
improve the security of PHP programs.
Shaun Clowes recently posted "A Study in Scarlet", identifying
common vulnerabilities in PHP applications; you can see it at:
http://www.securereality.com.au/studyinscarlet.txt
I agree with Rasmus Lerdorf
that several of these issues are present in other scripting languages,
and that a key issue is that you need to check input before depending on it.
However, Clowes makes some very good points too. In particular,
it's not just that PHP makes input "easier to get at".
PHP allows attackers to totally control all global variables unless the
program makes specific efforts to counter it (by explicitly resetting
the value).
That is VERY different from other scripting languages -
practically no other language is so trusting as to allow attackers to
control a program's own normal dataspace (globals) unless
specifically overridden.
What's particularly nasty is that some functions (including built-ins)
depend on global variables that may not be obvious, creating a vulnerability.
Currently, you'd have to look at every function called (even built-in ones!)
to ensure that every global function that's being used is reset
in every HTML page that references it (even indirectly).
When a new PHP edition comes along, you'd need to do the analysis again.
Making a mistake will silently create a security hole, but appear okay.
For example, a vulnerability exists in PHPLib because
attackers can set $_PHPLIB[libdir].
Thus, I contend that currently PHP makes it MUCH harder to develop secure
programs. There's no reason PHP needs to make developing secure programs
so hard; with a few minor changes to PHP it could be much safer.
In theory, a programmer could just set the option
register_globals to off. However, this isn't practical for many:
1. It may not be possible for some. Many websites are hosted by others,
and typical configurations don't allow this. Hosting sites may be
loathe to make such changes. E.g., for Apache, you have to
set "AllowOverride Options" for that directory so that an .htaccess file
can say "php_flag register_globals Off".
On Red Hat Linux and many others this isn't the default.
2. Even if you could set register_globals off, doing so would break
most existing scripts, a serious backward-compatibility problem.
3. Currently, PHP is awkward to use when register_globals is off.
So, I propose that PHP be modified in some way to make it easier
to develop secure programs. Here's one approach:
1. Devise a new variant of PHP, "Secure PHP" (SPHP), that is just PHP with
different configuration settings. When you use a different filename
extension (".sphp", ".php5", or whatever), you get Secure PHP instead.
You then set SPHP to, by default, have "register_globals off"
(as well as other settings to increase security).
Apache settings could be done with 'sphp_flag" or whatever.
This addresses the first two points above; you can now just use a
different extension, and with a different extension backwards
incompatibility is okay.
2. Add new functions so that having register_globals off isn't a problem.
By creating new standard functions, having register_globals off
could be easy to handle. Here are a few ideas for such functions:
function get_input ($variable)
# Return value of input named variable, or "" if unset.
# This pays attention to gpc_order, and looks at
# $HTTP_COOKIE_VARS, $HTTP_GET_VARS, and $HTTP_POST_VARS
function import_variables ($list_of_variables)
# Take a list of input (field) names as strings, and import any that exist.
function import_input_ifmatch($pattern, $list_of_variables)
# Take a list of input (field) names as strings, and import any that exist,
# but only if they match pattern (a Perl5 pattern, see preg_match).
# The pattern wll apply to each variable in its entirety, as though
# the pattern has '\A' prepended and '\z' appended.
function import_input_int($list_of_variables)
# Take a list of input (field) names as strings, and import any that exist
# as ints.
function import_input_double($list_of_variables)
# Take a list of input (field) names as strings, and import any that exist
# as ints.
For your abusement, here's an implementation of import_variables:
function import_variables () {
# Take a list of input (field) names as strings, and import any that exist.
$numargs = func_num_args();
$arg_list = func_get_args();
for ($i = 0; $i < $numargs; $i++) {
$v = $arg_list[$i];
global $$v;
$$v = get_input($v);
};
};
In SPHP, programs would generally begin with calls to these import
functions, so that programs would only import values that they wanted
(instead of trusting attackers not to create new variables), e.g.:
import_variables("name", "description");
import_input_ifmatch("yes|no", "bald");
import_input_int("age");
This is a little different than Zeev Suraski's 2001-07-29 post
(http://marc.theaimsgroup.com/?l=php-dev&m=99638994225888&w=2), because
it leaves the (less secure) mode of running PHP scripts running as-is.
Basically, this has a migration plan.
Someday in the future you might even make register_globals off
for "regular" PHP -- but this would at least give you a
transition approach. And if you're willing to change PHP to make
register_globals the default, that would be MUCH better from a security
standpoint. Even then, though, I think a set of "helper" functions to
make it easy to import "only the values we expect" is important --
developers will only write secure programs if it's easy to do the "right" way.
Anyway, I'd like to see future versions of PHP make it easy, not hard,
to write secure programs in. I hope this email helps!
--- David A. Wheeler
[EMAIL PROTECTED]
--
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]