SoFunction
Updated on 2025-04-08

Writing safe scripts in PHP 4.2

Original work: Kevin Yank  Reprinted from: (Congratulations on opening this again)

For a long time, one of the biggest selling points of PHP as a server-side scripting language is that it will automatically create a global variable for the values ​​submitted from the form. In PHP 4.1, PHP producers recommend an alternative to accessing submitted data. In PHP 4.2, they canceled that old practice! As I will explain in this post, the purpose of making such changes is for security reasons. We will look at PHP's new practices when processing form submissions and other data, and explain why this will improve the security of the code.

What's wrong here?

Take a look at the following PHP script, which is used to authorize access to a web page when the username and password entered are correct:
<?php 
// Check username and password
if ($username == 'kevin' and $password == 'secret') 
$authorized = true; 
?> 
<?php if (!$authorized): ?> 
<!-- Unauthorized users will give a prompt here ->
<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: ?> 
<!-- HTML content with security requirements -->
<?php endif; ?> 
OK, I believe that about half of the readers will say disdainfully, "It's so stupid-I won't make such a mistake!" But I promise that many readers will think, "Hi, there's no problem, I'll write it like this!" Of course, there will be a few people who will be confused by this question ("What is PHP?"). PHP is designed as a "good and easy" scripting language that beginners can learn to use in a very short time; it should also avoid beginners making the above mistakes.
Going back to the question just now, the problem in the code above is that you can easily gain access without providing the correct username and password. Just add ?authorized=1 at the end of the address bar of your browser. Because PHP will automatically create a variable for each submitted value - whether it is to automatically submit a form, URL query string or a cookie - this will set $authorized to 1, so an unauthorized user can also break through security restrictions.
So, how to simply solve this problem? Just set $authorized to false by default at the beginning of the program. This problem no longer exists! $authorized is a variable created entirely in the program code; but why do developers have to worry about every malicious user-submitted variable?

What changes have been made in PHP 4.2?

In PHP 4.2, the register_globals option in newly installed PHP is off by default, so the EGPCS value (EGPCS is the abbreviation of Environment, Get, Post, Cookies, Server - this is the full scope of external variable sources in PHP) will not be created as global variables. Of course, this option can also be enabled manually, but PHP developers recommend you turn it off. To implement their intentions, you need to use other methods to get these values.
Starting from PHP 4.1, EGPCS values ​​can be obtained from a specified array:
$_ENV -- Contains system environment variables
$_GET -- Contains variables in the query string and variables in the form where the method GET is submitted
$_POST -- Contains variables in a form with a submission method POST
$_COOKIE -- Contains all cookie variables
$_SERVER -- Contains server variables, such as HTTP_USER_AGENT
$_REQUEST -- Contains all contents of $_GET, $_POST and $_COOKIE
$_SESSION -- Contains all registered session variables
Prior to PHP 4.1, when developers turned off the register_globals option (which was also considered as a way to improve PHP performance), they had to use annoying names such as $HTTP_GET_VARS to get these variables. These new variable names are not only short, but they have other advantages.
First, let's rewrite the above mentioned code in PHP 4.2 (that is, turn off the register_globals option):
<?php 
$username = $_REQUEST['username']; 
$password = $_REQUEST['password']; 

// Check username and password
if ($username == 'kevin' and $password == 'secret') 
$authorized = true; 
?> 
<?php if (!$authorized): ?> 
<!-- Unauthorized users will give a prompt here ->
<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: ?> 
<!-- HTML content with security requirements -->
<?php endif; ?> 
As you can see, all I need to do is add the following two lines at the beginning of the code:
$username = $_REQUEST['username']; 
$password = $_REQUEST['password']; 
Since we want the username and password to be submitted by the user, we get these values ​​from the $_REQUEST array. Using this array allows users to freely choose the delivery method: query strings through URLs (for example, allowing users to automatically enter their certificates when creating bookmarks), through a submitted form, or through a cookie. If you want to limit the submission of certificates only through form (more precisely, through HTTP POST request), you can use the $_POST array:
$username = $_POST['username']; 
$password = $_POST['password']; 
Apart from "introducing" these two variables, the program code has not changed anything. Simply turning off the register_globals option prompts developers to gain a better understanding of which data is from external (untrusted) resources.
Please note that there is another minor problem here: the default error_reporting setting in PHP is still E_ALL & ~E_NOTICE, so if the two values ​​"username" and "password" are not submitted, trying to obtain these two values ​​from the $_REQUEST array or the $_POST array will not cause any error message. If your PHP program requires strict error checking, you also need to add some code to check these variables first.

But does this mean more input?

Yes, in simple programs like the above, using PHP 4.2 often increases the input volume. But, let’s take a look at the bright side--Your program is safer after all!
But seriously, PHP designers have not completely ignored your pain. There is a special feature in these new arrays that other PHP variables do not have, they are completely global variables. How will this help you? Let's expand our example first.
In order to make multiple pages in the site proven using username/password, we write our user authentication program into an include file():
<?php /*  */ 
function authorize_user($authuser, $authpass) 

$username = $_POST['username']; 
$password = $_POST['password']; 
// Check username and password
if ($username != $authuser or $password != $authpass): 
?> 
<!-- Unauthorized users will give a prompt here ->
<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 
exit(); 
endif; 

?> 
Now, our page just now will look like this:
<?php 
require(''); 
authorize_user('kevin','secret'); 
?> 
<!-- HTML content with security requirements -->
It's very simple, very clear, right? Now is the time to test your eyesight and experience -- What is missing in the authorize_user function?
There is no declaration in the function that $_POST is a global variable! In php 4.0, when register_globals is turned on, you need to add a line of code to get the $username and $password variables in the function:
function authorize_user($authuser, $authpass) 

global $username, $password; 
... 
In PHP, unlike other languages ​​with similar syntax, variables outside the function cannot be automatically obtained in the function. You need to add a line as explained above to specify that it comes from the global range.
In PHP 4.0, when register_globals is turned off to provide security, you can use the $HTTP_POST_VARS array to get the value of your form submitted, but you still need to import this array from the global scope:
function authorize_user($authuser, $authpass) 

global $HTTP_POST_VARS; 
$username = $HTTP_POST_VARS['username']; 
$password = $HTTP_POST_VARS['password']; 
But in PHP 4.1 and later, the special $_POST variable (and other variables mentioned above) can be used in all scopes. This is why it is not necessary to declare in the function that the $_POST variable is a global variable:
function authorize_user($authuser, $authpass) 

$username = $_POST['username']; 
$password = $_POST['password']; 

What impact does this have on the session?

The introduction of the special $_SESSION array actually helps simplify the session code. You don't need to declare the session variable as a global variable and then notice which variables are registered. You can now simply reference all your session variables from $_SESSION['varname'].
Now let's look at another example of user authentication. This time, we use sessions to mark a user who continues to stay on your website has been authenticated. First, let’s take a look at PHP version 4.0 (turn on register_globals):
<?php 
session_start(); 
if ($username == 'kevin' and $password == 'secret') 

$authorized = true; 
session_register('authorized'); 

?> 
<?php if (!$authorized): ?> 
<!-- Show HTML form to prompt the user to log in -->
<?php else: ?> 
<!-- HTML content with security requirements -->
<?php endif; ?> 
Like the first program, this program also has security vulnerabilities. Adding ?authorized=1 at the end of the URL can bypass security measures to directly access the page content. Developers can think of $authorized as a session variable and ignore that the same variable can be easily set through user input.
When we add our special array (PHP 4.1) and close register_globals (PHP 4.2), our program will look like this:
<?php 
session_start(); 
if ($username == 'kevin' and $password == 'secret') 
$_SESSION['authorized'] = true; 
?> 
<?php if (!$_SESSION['authorized']): ?> 
<!-- Show HTML form to prompt the user to log in -->
<?php else: ?> 
<!-- HTML content with security requirements -->
<?php endif; ?> 
Isn't it easier? You no longer need to register a normal variable as a session variable, you just need to set the session variable directly (in the $_SESSION array) and use it in the same way. The program gets shorter, and there is no confusion about what variable is a session variable!

Summarize

In this post, I explain the deeper reasons why PHP scripting language changes. In PHP 4.1, a special set of data was added to access external data. These arrays can be called in any range, which makes access to external data more convenient. In PHP 4.2, register_globals is turned off by default to encourage the use of these arrays to avoid inexperienced developers writing insecure PHP code.