Security proposal - "SPHP" and helper functions

From: Date: Tue, 07 Aug 2001 03:20:29 +0000
Subject: Security proposal - "SPHP" and helper functions
Groups: php.dev 
Request: Send a blank email to php-dev+get-62373@lists.php.net to get a copy of this message
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 dwheeler@dwheeler.com

« previous php.dev (#62373) next »