Insecure PHP Constants and Variables

Since the introduction of register_globals feature in PHP, there was a lot of discussion around the web criticizing this feature as a security risk. There established a perception that all websites on servers having register_globals enabled are insecure and vulnerable to hacking/injection. Consequently, the feature went to Off in PHP 4.2, deprecated in PHP 5.3 and completely removed in PHP 5.4. Even before all this, many web hosts disabled this feature. This caused problems to those not-by-profession PHP coders who rely on ease of use of PHP language to code their business or personal website.

Try Implementing register_globals on servers where it has been disabled or removed

If you are one of those who think that register_globals was insecure, then be prepared to consider PHP Variables and specially Constants equally insecure. I have something for you.

Below is an example code that demonstrates how a script may be compromised when register_globals directive is turned ON. The example was taken from php.net:

If the directive is ON, an attacker can use authorized query string variable with any value. Since anything other than false is true and passes the if check) to access /highly/sensitive/data.php.

What caused this attack to be successful? Is it really register_globals? Lets see.

Suppose we have PHP 5.4 where there is no register_globals. The previous example (after slight change) and the one given below using constants can still be insecure.

If the user is authenticated one, the constant AUTHORIZED will be defined as true and later on user will be allowed access to highly sensitive data. But what if user is not legitimate? In that case, there will be no constant defined and PHP will issue the following notice:

Notice: Use of undefined constant AUTHORIZED – assumed ‘AUTHORIZED’ in /path/to/www/dir/script.php on line 12.

The constant AUTHORIZED will be assumed by PHP as a string "AUTHORIZED" that will evaluate to true when casted to bool by PHP, resulting in everyone to pass the
if( AUTHORIZED ) check, as it is the way PHP works.

User was not authorized to get access to restricted areas, but the script let it do. There was no register_globals, but the same sample script is still insecure. So, where the problem is?

The problem lies in Bad Coding Practices.

PHP does not require you to initialize variables before using (but it does not mean that you do not have to). However, if you try to use an uninitialized variable, PHP treats it as null and issues a “Notice” that the variable is undefined. On the other hand, undefined constants are treated by PHP as string and a “Notice” is issued.

To avoid such problems, what a PHP developer needs to do is:

  • Make sure that variables are always initialized and constant always defined before they are used;
  • Turn ON all PHP Notices, Warnings and Errors in the development using error_reporting(E_ALL|E_STRICT);. When you move your code to production server, replace the above line with error_reporting(0); ini_set('display_errors','0');. As of PHP 5.4, E_ALL includes E_STRICT, so it is sufficient to use error_reporting(E_ALL); on development servers that have PHP 5.4+.

The secure authentication script should look like:

Or, with constant:

Properly initializing variables with very strict error reporting always benefits you. It not only improves you coding skills, but also makes your code more secure and reliable. There was no security problem with register_globals but the ease of use of PHP combined with poor coding practices adopted by coders lead it to become a security threat, causing it to die even when it was still needed. Now when register_globals is officially dead, your code is still no more secure and even your variables and constants can harm your script depending upon how you use them.