Article
Write Secure Scripts with PHP 4.2!
How does PHP 4.2 change things?
As of PHP 4.2, a fresh PHP installation has the register_globals option turned off by default, so EGPCS values (EGPCS is short for Environment, Get, Post, Cookies, Server -- the full range of external variable sources in PHP) are not created as global variables. Yes, this option can still be turned on manually, but the PHP team would prefer it if you didn't. To comply with their wishes, you'll need to use an alternate method to get at these values.
Beginning with PHP 4.1, EGPCS values are now available in a set of special arrays:
$_ENV-- Contains system environment variables$_GET-- Contains variables in the query string, including from GET forms$_POST-- Contains variables submitted from POST forms$_COOKIE-- Contains all cookie variables$_SERVER-- Contains server variables, such asHTTP_USER_AGENT$_REQUEST-- Contains everything in$_GET,$_POST, and$_COOKIE$_SESSION-- Contains all registered session variables
Prior to PHP 4.1, developers who worked with register_globals turned off (this was also considered a good way to boost PHP performance a little) accessed these values using cumbersome arrays like $HTTP_GET_VARS. These new variable names are not only shorter, but they have some nice new features as well.
First, let's re-write the broken script from the previous section for use under PHP 4.2 (i.e. with register_globals turned off):
<?php
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];
$PHP_SELF = $_SERVER['PHP_SELF'];
// Check the username and password
if ($username == 'kevin' and $password == 'secret')
$authorized = true;
?>
<?php if (!$authorized): ?>
<!-- Unauthorized users are prompted for their credentials -->
<p>Please enter your username and password:</p>
<form action="<?=$PHP_SELF?>" method="POST">
<p>Username: <input type="text" name="username" /><br />
Password: <input type="password" name="password" /><br />
<input type="submit" /></p>
</form>
<?php else: ?>
<!-- Super-Secret HTML content goes here -->
<?php endif; ?>
As you can see, all I had to do was add three lines to the top of the script:
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];
$PHP_SELF = $_SERVER'['PHP_SELF'];
Since we're expecting the username and password to be submitted by the user, we grab these values out of the $_REQUEST array. Using this array allows users to pass in the values by any means at their disposal: through the URL query string (e.g. to allow users to create a bookmark that enters their credentials automatically for them), by a form submission, or as a cookie. If you would prefer to limit the methods by which they can submit their credentials to form submissions only (or more precisely, HTTP POST requests, which can be simulated without a form submission if push comes to shove), you could use the $_POST array instead:
$username = $_POST['username'];
$password = $_POST['password'];
$PHP_SELF = $_SERVER['PHP_SELF'];
We also fetch the commonly-used PHP_SELF variable out of the array of server variables; like the form variables, it isn't created automatically with register_globals disabled. Since it's only used once in the script, you'll probably prefer just referencing it directly in your form code:
<form action="<?=$_SERVER['PHP_SELF']?>" method="POST">
Other than 'allowing in' these three variables, the script hasn't changed at all. Turning register_globals off simply forces the developer to be aware of data that comes in from outside (untrusted) sources.
Note for the Nitpickers: The default error_reporting setting of PHP is still E_ALL & ~E_NOTICE, so if the 'username' and 'password' values haven't been submitted, attempting to pull them out of the $_REQUEST or $_POST array will not produce an error message. If you're using a stricter level of error checking on your PHP setup, you'll need to add a little more code to check if these variables are set first.