register_globals

Overview

edit

Register globals is a deprecated feature of PHP. The feature causes data passed to a PHP script via cookies or GET and POST requests to be made available as global variables in the script.

Register globals is convenient but extremely dangerous, often allowing an attacker to overwrite variables in a script simply by adding parameters to requests. While the feature has been disabled by default since PHP 4.2.0 (which was released April 22, 2002), hosting providers often enable the feature to provide compatibility with old scripts.

Example

edit

Here's a simple example of how register globals can present a security risk. The following PHP fragment is written with the expectation that $file will set by a user submitting an HTML form containing a <select name="file"><option>file1</option><option>file2</option><option>...</option></select> tag.

<?php
# ...
# display the file specified by the <select name="file">...</select> form element
readfile( '/path/to/file/dir/' . $file );
# ...

Forcing the script to display a sensitive file containing passwords is simply a matter of making a GET request. For example, the following request could cause the script to display the contents of LocalSettings.php:

http://example.com/example.php?file=../../../../../var/www/mediawiki/LocalSettings.php

While this would seem to rely on detailed knowledge of the server's file system, it is fast and easy to write scripts that explore many different paths very quickly.

Disabling Register Globals

edit

When possible, ensure that register globals is disabled by setting register_globals to off in your php.ini file.

In cases where you cannot edit your php.ini file (or cannot disable the feature globally), you may still be able to disable the feature via your web server's configuration files. Note that register_globals cannot be set at runtime using PHP's ini_set() function.


For the Apache Web Server, use the php_flag directive in a .htaccess file to disable register globals on a per-directory tree basis.

php_flag register_globals off

Then use phpinfo() to confirm that ini_get() is set to off.

A detailed tutorial on the use of .htaccess files is outside of the scope of this documentation. For further information, read Apache Tutorial: .htaccess files.

Protecting MediaWiki from Register Globals

edit

Do not use global variables in script paths

edit

It is best to avoid using global variables in script paths. You'll be happier because your code reviewers will be happier and your code will have fewer vulnerabilities.

<?php
// Get common functions
require( dirname(__FILE__).'/CommonFunctions.php' );

Make sure code is only executed in the right context

edit

If for some reason it's absolutely necessary to use a global variable like this, you can protect it using some boilerplate code, present in many extensions:

<?php

if ( !defined( 'MEDIAWIKI' ) ) {
    die( 'Not a valid entry point.' );
}
require( "$IP/extensions/MyExtension/CommonFunctions.php" );
...

This ensures that the code can only be executed after MediaWiki is initialised. You can be sure that MediaWiki will set the $IP variable when it initialises. This boilerplate is unnecessary for files that only contain classes.

Sanitize custom global variables before use

edit

Ensuring that code is executed in the correct context will only protect MediaWiki's default variables from register globals. Custom global variables will not be protected. In the following example, if register globals is enabled an attacker could still overwrite $myExtPath.

<?php
if ( !defined( 'MEDIAWIKI' ) ) exit;

if ( !isset( $myExtPath ) ) {
    $myExtPath = "$IP/extensions/MyExtension";
}
require( "$myExtPath/CommonFunctions.php" );
...

If you must use a custom global variable (like $myExtPath in the example above), ensure that it is initialized with a default value and is not used across include() or require().

We could make the above example safer by:

  • ensuring that the script always sets $myExtPath; and
  • not using $myExtPath in $myExtPath/CommonFunctions.php unless we also set it in this file.
<?php
if ( !defined( 'MEDIAWIKI' ) ) exit;
$myExtPath = "$IP/extensions/MyExtension";
require( "$myExtPath/CommonFunctions.php" );
...

Configure extensions only after their setup file is included

edit

Because MediaWiki uses global variables for its configuration namespace, this means that all extensions must be configured in LocalSettings.php after their setup file is included.

<?php

$kittyCatName = 'Yoshi'; // set this here to avoid register_globals vulnerabilities

function writeKittyName() {
    global $wgOut;
    global $kittyCatName; // definitely safe
    $wgOut->addHTML( htmlspecialchars( $kittyCatName ) );
}

In LocalSettings.php

require( "$IP/extensions/KittyCat/KittyCat.php" ); // sets default variables
$kittyCatName = 'Puss'; // override the default

See also

edit