超越PHP PHP动态 | 经典文章 | CLASS | 相关下载 | 常见问题 | FORUM | WIKI | 在线手册
Site search:    
previousError ReportingUser Submitted Datanext
Last updated: Fri, 22 Jun 2007

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
add a note about notes
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>&nbsp;</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.

add a note about notes
previousError ReportingUser Submitted Datanext
Last updated: Fri, 22 Jun 2007
view source | feedback | send page | sitemap | aboutus   
Copyright ® 2002-2003 PHPE.NET. All rights reserved
Last updated:2002-11-22