|
|
 |
Using Register Globals
One feature of PHP that can be used to enhance security is configuring PHP with
register_globals = off.
By turning off the ability for any user-submitted variable to be injected
into PHP code, you can reduce the amount of variable
poisoning a potential attacker may inflict. They will have
to take the additional time to forge submissions, and your
internal variables are effectively isolated from user
submitted data.
While it does slightly increase the amount of effort required
to work with PHP, it has been argued that the benefits far
outweigh the effort.
例子 5-14. Working with register_globals=on <?php
if ($username) { // can be forged by a user in get/post/cookies
$good_login = 1;
}
if ($good_login == 1) { // can be forged by a user in get/post/cookies,
fpassthru ("/highly/sensitive/data/index.html");
}
?> |
|
例子 5-15. Working with register_globals = off <?php
if($_COOKIE['username']){
// can only come from a cookie, forged or otherwise
$good_login = 1;
fpassthru ("/highly/sensitive/data/index.html");
}
?> |
|
By using this wisely, it's even possible to take preventative
measures to warn when forging is being attempted. If you know
ahead of time exactly where a variable should be coming from,
you can check to see if submitted data is coming from an
inappropriate kind of submission. While it doesn't guarantee
that data has not been forged, it does require an attacker
to guess the right kind of forging.
例子 5-16. Detecting simple variable poisoning <?php
if ($_COOKIE['username'] &&
!$_POST['username'] &&
!$_GET['username'] ) {
// Perform other checks to validate the user name...
$good_login = 1;
fpassthru ("/highly/sensitive/data/index.html");
} else {
mail("admin@example.com", "Possible breakin attempt", $_SERVER['REMOTE_ADDR']);
echo "Security violation, admin has been alerted.";
exit;
}
?> |
|
Of course, simply turning off register_globals does not mean code
is secure. For every piece of data that is submitted, it
should also be checked in other ways.
User Contributed Notes Using Register Globals |
 |
visionriver at yahoo dot com
07-Nov-2003 05:14 |
|
This is a note for newbies to PHP - from one to another. Don't
underestimate the important 'down the road' implications of
register_globals on/off. It's quite fundamental and particularly in shared
UNIX/Apache server environments. If you're working with register_globals ON
(which it seems most hosting companies default to, due to the historic
background of php) then you have session problems... you may not even be
aware of them initially. If you're experiencing unanticipated responses
from your application from time to time then these are very likely to be
session related.
Here's the lesson I recently learned the hard way:
Turn register_globals OFF and don't even bother attempting to manage your
php.ini settings through your php code. Create a .htaccess file in your
document root that contains at least the following settings:
1. Set
register_globals to off. 2. Load your fixed include paths. 3.
Relocate your session file storage folder away from the default '/tmp' -
including whatever garbage collection settings are appropriate for you. For
all intents and purposes this is like inviting your real-life garbage
collector into your home and asking them to decide what they think you
should throw away today...
Here's the .htaccess
code:
php_flag register_globals off php_value session.save_path
/home/user/siteroot/sess/users php_value session.gc_maxlifetime
xxx php_value include_path .:/home/user/siteroot.com/sess php_value
auto_prepend /home/user/siteroot.com/sess/path_file.php
Doing this
has virtually eliminated all of my issues (PHP 4.2.3), which seemed to be
piling up quite inexplicably. Right around the time you start thinking it's
your hosting service provider - like when you start receiving the
following: "Warning: Failed to write session data (files). Please
verify that the current setting of session.save_path is correct (/somedir)
in Unknown on line 0". That Unknown on Line 0 is Apache sending
php/you a message to turn globals off and generally sort out your session
management.
Finally, trawling all of the php information/support
sites you may be tempted to think that you can only get around your issues
by installing your own session_handler. There's no need for that unless
your site is handling massive volumes of traffic and you need database
support. I tried that, but ran straight into the same problems again. PHP
does the job very well. You just need to make sure that your session
environment isn't contaminated and set your include paths before handing
your user over to php.
Bill
|
|
cameronNO_SPAM at tripdubdev dot com
05-Nov-2003 03:03 |
|
Here's a useful bit of code I created (can be used for ANY of the different
types of variables GET, POST, COOKIES, etc...)
It's basically a
filter that will allow you to pre-filter ALL variables before using them in
your code, reducing risks of security holes at the application
level.
Any feedback is greatly appreciated.
<?
$alphabet="\r\n
abcdefghijklmnopqrstuvwxyz1234567890<>=/._"; $post=$_POST; $get=$_GET; $postcount=count($post)
-1; $getcount=count($get)
-1; $getkeys=array_keys($get); $postkeys=array_keys($post);
while($getcount>0)
{ $key=$getkeys[$getcount]; $variable=$get[$key];
$variable=$variable1=trim(strtolower($variable));
$vnum=0;
while($variable2=$variable1[$vnum]) {
if(!strstr($alphabet,$variable2) || $variable2=="\"")
{
$variable=str_replace($variable2,'',$variable);
} $vnum=$vnum+1; }
$_GET[$key]=$variable; $getcount=$getcount-1;
}
while($postcount>0)
{
$key=$postkeys[$postcount]; $variable=$post[$key];
$variable=$variable1=trim(strtolower($variable));
$vnum=0;
while($variable2=$variable1[$vnum]) {
if(!strstr($alphabet,$variable2) || $variable2=="\"")
{
$variable=str_replace("$variable2","",$variable);
} $vnum=$vnum+1;
} $_POST[$key]=$variable;
$postcount=$postcount-1; } ?>
|
|
davida at trib dot com
19-Apr-2003 02:55 |
|
Quite a few of the above examples of automatically registering globals
ignore the $_FILES (or $HTTP_POST_FILES) superglobal. These are also a
little more complex because these are multi-dimensional associative arrays.
Before posting a simplified function to register file data, I'll note
again that this probably shouldn't be used except to get code working
quickly while updating it to use unregistered globals (and even then you're
probably better turning global registration on for the
site).
function registerFiles(){ global
$HTTP_POST_FILES;
foreach( $HTTP_POST_FILES as $varname =>
$fileinfo ){ $GLOBALS[$varname] =
$fileinfo["tmp_name"]; $GLOBALS[$varname.'_name'] =
$fileinfo["name"]; } }
|
|
solar at heliacal dot net
16-Apr-2003 11:47 |
|
This construct is handy for getting similar functionality to having
register_globals on, but being able to selectively import variables for
your form
submissions.
$param_list=array( 'some_input', 'some_input2' );
/*
this will work whether it was GET or POST, doesn't make a difference
*/ foreach($param_list as $param)
@$$param=${"_$_SERVER[REQUEST_METHOD]"}[$param];
If you
have inputs in your form with names some_input and some_input2, this
snippet would have created $some_input and $some_input2. This way you can
just list all your inputs in $param_list and only those are imported.
|
|
Damon
02-Mar-2003 01:25 |
|
I wrote this function to provide a way to automatically register the
globals for form variables by parsing the file for input names and textarea
names. Since I have this function in an include file, you need to pass it
$_SERVER and $_GET/POST since these don't seem to be available to include
files...? Also, it uses djresonance's code to allow specifiing which
variables to register globally and thus allow access to ENV, COOKIE, etc.
To top it all off, if it finds a variable passed to the script that wasn't
requested or wasn't found through parsing, it triggers a security threat
page.
<?php
function registerGlobals(&$serverVars,
&$methodVars) {
$numArgs = func_num_args();
$args
= func_get_args();
if ($numArgs == 2) {
$f =
fopen($serverVars['SCRIPT_FILENAME'], 'r');
$buffer =
'';
fclose($f);
$matches = array();
while
(!feof($f))
$buffer .= fgets($f, 4096);
preg_match_all('/<(input|textarea).*?name=\"([\w]+)\".*?>/',
$buffer, $matches, PREG_PATTERN_ORDER);
foreach
($methodVars as $name => $value) {
if
(in_array($name, $matches[2])) {
global
${$name};
${$name} = $methodVars[$name];
} else {
reportSecurityThreat($serverVars['REMOTE_ADDR']);
return false;
}
}
return true;
} elseif ($numArgs > 2) {
foreach ($methodVars as $name => $value) {
if
(in_array($name, $args)) {
global ${$name};
${$name} = $methodVars[$name];
} else
{
reportSecurityThreat($serverVars['REMOTE_ADDR']);
return false;
}
}
return true;
} else
die("Invalid number of
arguments. Usage: registerGlobals(\$_SERVER, \$_GET/POST, ['var1',
'var2'...]);");
}
function reportSecurityThreat($ip)
{
print <<<END
<table width="100%"
height="100%">
<tr>
<td
align="center" valign="center">
<table>
<tr>
<td
align="center"><span style="font-family: Arial,
Helvetica, sans-serif; font-size: 30px; color: #ff0000;">Security
Threat Detected</span></td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td><span
style="font-family: Arial, Helvetica, sans-serif; font-size: 15px;
color: #000000;">This security threat from $ip has been logged and
the administrator notified.</span></td>
</tr>
</table>
</td>
</tr>
</table>
END;
}
?>
|
|
sir_tuam at web dot de
27-Feb-2003 07:56 |
|
If you are on a vhost with register_globals=on (like me):
You can
include in your .htaccess
php_flag register_globals
off
(just like Arjan proposed with "on") to increase your
local security.
|
|
|
19-Feb-2003 04:31 |
|
With respect to the "same problem in C, don't change compiler, just
fix the code", you usually use the compiler to check if your code is
ok, just because no compiler will allow exactly eg. Ansi-C 99 and no more
and no less, and because you probably can't write large pieces of code with
the standards documents at your hands. So, grinding your code through
several compilers is likely to show you different classes of errors you may
have made, relying on only one compiler can be bad.
|
|
james at ironstone dot com dot au
23-Jan-2003 07:05 |
|
If you're using global variables to cope with access levels within your
interactive website or application, the safe way is to store the username
and password used in the cookies and verify it on every page by having the
same auth code included.
That way the only hacking that can be done
is packet interception to grab passwords (SSL if you're worried about that)
or somebody hacking someone else's cookies in IE or something by getting to
their computer. (IE settings might have a fix for this although if IE is
using SSL to get a cookie one would hope it encrypts the stored data but
you never know...)
I think reg_global_vars is like any other tool,
its only a security risk if you use it unaware of the possibilities. For
non-security related variables its a quick and convenient tool, and for
security related ones its something to be worked around or avoided.
|
|
jeff at ourexchange dot net
31-Dec-2002 06:38 |
|
Another way of registering the variables is by
calling
extract($_REQUEST);
which will put everything from
$_GET and $_POST into the global scope. It doesn't do anything for
sessions, cookies, etc, but then again, you can just call those from
$_COOKIE and $_SESSION.
|
|
s0lar1s8@_hot_mail
20-Dec-2002 10:32 |
|
Not using the registers, I would assume that this example would also
prevent a hacker from changing the username via POST or GET, since I am
setting the username cookie and hash cookie for the entire session. The
cookies are only set once and the hash key is known only to me.
Example:
// Do all this before the html header - php post self //
User gave his/her username and pressed submit. $hidden_hash_var =
'this_is_your_secret_hash_key'; if ($username) { // valid login - set
cookie now for session $id_hash= md5($username.$hidden_hash_var);
$secure = 1; // 1 for https - use 0 for http $site =
$HTTP_HOST; // your site
setcookie("username","$username",0,"/","$site",$secure);
setcookie("id_hash","$id_hash",0,"/","$site",$secure);
}
// check to see if the user is logged in (cookie set and hash
matches) $LOG_IN = 0; if ($username && $id_hash) { // Checks
each post $hash=md5($username.$hidden_hash_var); if ($hash ==
$id_hash) { $LOG_IN = 1; // they'd have to guess this var }
} // end - if i'm mistaken let me know. 12/2002
|
|
rjm1 at yahoo dot com
03-Nov-2002 06:55 |
|
On the note about putting "php_flag register_globals on" in your
.htaccess to allow a transition period:
You must have something like
this in your httpd.conf file for that to work.
<Directory
/whatever/> AllowOverride
Options </Directory>
(AllowOverride All will also
work.)
Took me a while to dig that out of the manual, so I thought
I'd post it.
--RJ
|
|
Arjan
01-Nov-2002 03:10 |
|
One can even set it per directory, in Apache's .htaccess file:
php_flag register_globals on
Of course, only to make complex old
code run!
Likewise I would think one can disable it, in case one
cannot control php.ini on a shared web server and wants the setting to be
off while the server's administrator wants the keep the old default.
|
|
nhallman [at] ciu [dot] edu
25-Oct-2002 02:51 |
|
It's possible to set register_globals to "off" on a site-by-site
basis via Apache, thus overriding the "global" setting of
register_globals in php.ini:
In httpd.conf:
<VirtualHost
127.0.0.1> ServerName localhost DocumentRoot
/var/www/html/mysite php_value register_globals 0 (or 1 for
"on") </VirtualHost>
That way, sites with old
code can have register globals turned on, but for all new developments it
will be disabled.
|
|
sorry, too much spam
10-Oct-2002 11:28 |
|
If you are forced to have register_globals=on because of old code, but you
are starting a new project and you want to make sure you don't accidentally
use global vars in your new code, you can run this snippet to unset any
global vars that were set.
$arr =
array_merge(&$_ENV,&$_GET,&$_POST,&$_COOKIE,&$_SESSION); while(list($key)
= each($arr)) unset(${$key});
I am sure this does not provide any
extra security, and is certainly not as effective as setting
register_globals=off, but should keep you from writing more 'bad' code by
forcing you to use super globals.
Anybody have a better way? please
post
|
|
djresonance at yahoo dot com
23-Aug-2002 10:37 |
|
There are a few functions posted on this page that can help to make it seem
that register_globals is turned on. However, that defeats the whole
purpose of having register_globals off in the first place. I think a
better solution is to register each variable along with the request method
from which that variable came seperatly. To that end, I wrote a function
which does exactly that. This function accepts a variable number of
arguments. The first argument should be the request method you want to get
the variable from, and the rest are the variables that you want to register
in the global namespace. I used $HTTP_*_VARS instead of $_* for
compatibility with older versions of php:
/** * Registers global
variables * * This function takes global namespace $HTTP_*_VARS
variables from input and if they exist, * register them as a global
variable so that scripts can use them. The first argument * signifies
where to pull the variable names from, and should be one of GET, POST,
COOKIE, ENV, or SERVER. * */ function pt_register() {
$num_args = func_num_args(); $vars = array();
if
($num_args >= 2) { $method =
strtoupper(func_get_arg(0));
if (($method != 'SESSION')
&& ($method != 'GET') && ($method != 'POST') &&
($method != 'SERVER') && ($method != 'COOKIE') && ($method
!= 'ENV')) { die('The first argument of pt_register must be
one of the following: GET, POST, SESSION, SERVER, COOKIE, or ENV');
}
$varname = "HTTP_{$method}_VARS";
global ${$varname};
for ($i = 1; $i < $num_args; $i++)
{ $parameter = func_get_arg($i);
if
(isset(${$varname}[$parameter])) { global
$$parameter; $$parameter = ${$varname}[$parameter];
}
}
} else { die('You must
specify at least two arguments'); }
}
You can then
register your global variables for use like this:
// register a GET
var pt_register('GET', 'user_id', 'password'); // register a server
var pt_register('SERVER', 'PHP_SELF'); // register some POST
vars pt_register('POST', 'submit', 'field1', 'field2', 'field3');
|
|
|
23-Jul-2002 07:53 |
|
Having global variables or indeterminate origin was a pain, but like many
things people rely on it. In a serious production environment, this should
be off (if only I had known this could have been turned off earlier).
However many beginners will have learnt to use this facility, so there
should be a means to turn it on of off on a per site (or per page) basis.
After all the server's security model shouldn't allow php to be running as
a user that has serious access to break things anyway. Any perceived
breech should only be a flaw in the php sites coding. The responsiblity
for fixing this is in the author of site, whom should write better php,
putting all code inside classes, so global variables need to be explicity
accessed for example. Flaws in C are exactly the same, don't change the
compiler, just fix your code.
|
|
 |
| |