Security with PHP Superglobals

January 7th, 2003 by David Lechnyr in

Wouldn't it be great to have a way to isolate variables based on how the data is assigned in the first place?
Your rating: None

A few years ago, my wife and I decided to go on a skiing trip up north. To reserve skiing equipment, you had to give 24-hour advance notice using the ski lodge's on-line web site. The catch was my wife had asked me to make the reservations 23 hours before the deadline.

So I got to thinking and examined the on-line web site, which would not let you make any reservations within the 24-hour timeframe. However, once you selected an appropriate date, I noticed the URL was:

https://www.somewhere.com/reservations.php?date=01-23-01

It occurred to me that although they had locked down security on what dates I could choose from, the final value was placed in a GET statement at the end of the web address. I modified the web address to use “date=01-22-01” and indeed, our skies were waiting for us first thing the next morning (we paid for them, of course).

This innocent yet practical example is only one of the dangers we must be aware of when using any programming language that can be used in ways we did not intend, which leads us to our discussion of PHP Superglobals.

Forms

To understand Superglobals, it is critical that you understand how data is passed from one web page to another (e.g., forms). Specifically, you must be aware of two methods known as GET and POST. You also should be familiar with the HTML <FORM> statement (a good reference is www.w3.org/TR/html401/interact/forms.html).

You've probably seen something like this before:

<form name="form1" method="post" action="process.php">
   <p>Please enter your name:</p>
   <p><input type="text" name="yourname" /></p>
   <p><input type="button" name="Submit" value="Submit" /></p>
</form>

This is standard, nothing-fancy HTML form code that asks for some information and then submits the data to the file process.php. The critical bit here is the method declaration, which tells the form how to submit the data; for this, we need to digress for a moment or two (hold your breath):

For those who recall the early days of HTML, forms were provided by means of the <ISINDEX> HTML tag. By inserting this tag into the HEAD of your HTML documents, a text field appeared where you could supply out input. As the new HTML+ standard evolved, a <FORM> tag was designed and could be used with a METHOD attribute of GET, POST or PUT. So, this leaves us with a few different ways to send our data.

GET

With GET, variables and their values are sent in the header of the URL request appended as part of the URL itself. The limitation is that web addresses (URLs) are limited to 8,192 characters; if the amount of data is too long, it will be truncated. Also, even with an SSL connection, the data is not encrypted because it is part of the web address.

For example, a web page might have a form statement like this:

<form name="form1" method="get" action="process.php">
   <p>Please enter your name, e-mail address, and a comment:</p>
   <p><input type="text" name="yourname" /></p>
   <p><input type="text" name="email" /></p>
   <p><input type="text" name="comment" /></p>
   <p><input type="button" name="Submit" value="Submit" /></p>
</form>

When you clicked Submit, your web browser would take the values you filled out in the form and redirect you to this web address:

http://www.fluffygerbil.com/process.php?yourname=fred+smith&email=fred@nowhere.com&comment=I+have+no+comment

Notice how the values of the form are part of the web address itself? That's the essence of GET.

For the curious, what is actually sent in the raw HTTP transmission to accomplish this transaction is:

GET /process.php?yourname=fred+smith&email=fred@nowhere.com&comment=I+have+no+comment HTTP/1.0
Accept: image/gif, image/x-xbitmap, image/jpeg, */*
Accept-Language: en-us
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461)
Host: www.fluffygerbils.com
Connection: keep-alive
POST

With POST, the variables and their values are sent in the body of the URL request, not the header. The advantages of this type of data transmission is there is no limit to the size of the data being sent; it is contained in the body of the HTTP request, not the header. Also, if you're using an SSL connection, the data will be encrypted too—what a deal. For example, consider a web page with a form statement like this:

<form name="form1" method="post" action="process.php">
   <p>Please enter your name, e-mail address, and a comment:</p>
   <p><input type="text" name="yourname" /></p>
   <p><input type="text" name="email" /></p>
   <p><input type="text" name="comment" /></p>
   <p><input type="button" name="Submit" value="Submit" /></p>
</form>

When you clicked Submit, your web browser would take the values you filled out in the form and redirect you to this web address: http://www.fluffygerbil.com/process.php

Notice how the values of the form are not part of the web address itself? That's the essence of PUT.

For the curious, what is actually sent in the raw HTTP transmission to accomplish this transaction is:

POST /process.php
HTTP/1.0Accept: image/gif, image/x-xbitmap, image/jpeg, */*
Accept-Language: en-us
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461)
Host: www.fluffygerbils.com
Content-Length: 94
Pragma: no-cache
Connection: keep-alive

yourname=fred+smith
email=fred@nowhere.com
comment=I+have+no+comment
So What?

So, why is all this background information useful? When you install PHP 4.2.2 or later, you might happen to notice that when compiling PHP, it states:

+--------------------------------------------------------------------+
|                         *** NOTE ***                               |
|            The default for register_globals is now OFF!            |
|                                                                    |
| If your application relies on register_globals being ON, you       |
| should explicitly set it to on in your php.ini file.               |
| Note that you are strongly encouraged to read                      |
| http://www.php.net/manual/en/security.registerglobals.php          |
| about the implications of having register_globals set to on, and   |
| avoid using it if possible.                                        |
+--------------------------------------------------------------------+

This means PHP will be ultra-paranoid about the data passed to it and will require you to state from which method the data should be coming. Also, you should be aware that more ways are available to send data to your PHP pages than GET and POST:

Superglobals

This brings us to Superglobals a relatively new concept to PHP. For example, the above diagram presents a slight problem: if you're working with the variable $yourname, how do you know that during your script it hasn't been redefined by one of these six other methods of variable assignment by someone attempting to hack into your script? For example, imagine having someone who has managed to upload a PHP script to your web server that performs the following (php exploit by Daniel Phoenix):

<?phpsetcookie("test","../../../../../../etc/passwd");echo "cookie inserted";?>

Wouldn't it be great to have a way to isolate variables based on how the data gets assigned in the first place? Superglobals allow you to specify which variables received by a specific method should be used.

Superglobals are PHP's attempt at helping you determine where a particular value comes from. If you haven't heard of this new feature as of PHP 4.1.0, you'll want to start adapting to it. Most PHP training books don't touch this subject, so you will need to be aware of how to transition to this new input method. Ultimately, you should re-visit your /usr/local/lib/php.ini file and make the following change:

register_globals = Off

This will prevent the ability for any user-submitted variable to be injected into your PHP code and 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. If a user then tried to fill out a form, the server wouldn't assign any data to the global variables $name, $email or $comment. Instead, it would divide up the data into the following hashed arrays:

$_POST['name']$_POST['email']$_POST['comment']

The main Superglobal arrays are:

  1. $_GET['variable'] - Variables provided to the script via HTTP GET. Analogous to the deprecated HTTP_GET_VARS array

  2. $_POST['variable'] - Variables provided to the script via HTTP POST. Analogous to the deprecated $HTTP_POST_VARS array

The other, less-common Superglobal arrays are:

  1. $_COOKIE['variable'] - Variables provided to the script via HTTP cookies. Analogous to the deprecated $HTTP_COOKIE_VARS array

  2. $_REQUEST['variable'] - Variables provided to the script via any user input mechanism (GET, POST, COOKIE) and which therefore cannot be trusted.

  3. $_GLOBALS['variable'] - Contains a reference to every variable which is currently available within the global scope of the script. The keys of this array are the names of the global variables.

  4. $_SERVER['variable'] - Variables set by the web server or otherwise directly related to the execution environment of the current script. Analogous to the deprecated $HTTP_SERVER_VARS array

  5. $_FILES['variable'] - Variables provided to the script via HTTP post file uploads. Analogous to the deprecated $HTTP_POST_FILES array

  6. $_ENV['variable'] - Variables provided to the script via the environment. Analogous to the deprecated $HTTP_ENV_VARS array

  7. $_SESSION['variable'] - Variables which are currently registered to a script's session. Analogous to the deprecated $HTTP_SESSION_VARS array

For more details, see www.php.net/manual/en/reserved.variables.php.

So instead of $name being set to “John”, you would either have $_GET['name'] = "John" or possibly $_POST['name'] = "John" depending on how the form data was submitted. The advantage is that you will know:

  1. $name can never be faked; if your script sets its value, that's the value!

  2. The $_GET and $_POST arrays help you to determine if the user appended the data as part of the URL or as part of the request body; therefore you don't have to worry about having a form accepting POST data and having the values change by someone sending a hacked URL with GET data appended to the URL. This will make sense shortly, so hang on...

  3. These Superglobals allow you to compartmentalize not only your variable's values, but also how the values were provided to the server in the first place. Someone attempting to hack into your server will have a very difficult time bypassing this.

Final Thoughts

Programming with PHP can be a frustrating experience as of late. Security measures prevent data from being easily assigned to variables, ISPs typically implement PHP without consideration for their audience, and newcomers to PHP tend to be taken aback by such terms as GET, POST, Superglobals and so forth. However, a little knowledge can go a long way, and hopefully this article has helped you in your quest.

Resources

This document was lovingly handcrafted on a Dell Latitude C400 laptop running Slackware Linux 8.1. This document was prepared based on PHP 4.3.0.

David Lechnyr is a network manager for the Human Resources department of the University of Oregon. He holds a Master's Degree in social work, along with his MCSE+I, CNE and CCNA certifications. He has been working with Linux for the past six years, with an emphasis on systems security, network troubleshooting and PHP/MySQL integration.

__________________________


Special Magazine Offer -- Free Gift with Subscription
Receive a free digital copy of Linux Journal's System Administration Special Edition as well as instant online access to current and past issues. CLICK HERE for offer

Linux Journal: delivering readers the advice and inspiration they need to get the most out of their Linux systems since 1994.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Anonymous's picture

Re: Security with PHP Superglobals

On September 14th, 2004 Anonymous says:

You neglected to continue with your http://www.fluffygerbil.com/process.php example and how to use the superglobals. I'm scratching my head wondering where the rest of the article is!

Anonymous's picture

Re: Security with PHP Superglobals

On June 29th, 2004 Anonymous says:

"therefore you don't have to worry about having a form accepting POST data and having the values change by someone sending a hacked URL with GET data appended to the URL. This will make sense shortly, so hang on... "

Is there an addional explanation that was supposed to be written regarding the last line of this quote? I'm not sure how using $_GET['var'] will prevent users from still putting their own value in a querystring to be processed by the server. I'm sure it's just a simple explanation but it's something I'm curious about.

Anonymous's picture

Re: Security with PHP Superglobals

On June 15th, 2004 Anonymous says:

Wow, are you a clear writer. Thank you so much for the concise help, I'd been trying to figue out why my form changes worked on mozilla but not opera, yes in netscape no in IE.
Cheers from downunder.

Anonymous's picture

Re: Security with PHP Superglobals

On June 2nd, 2003 Anonymous says:

thank you

Anonymous's picture

Re: Security with PHP Superglobals

On January 13th, 2003 Anonymous says:

Excellent article. The breakdown of parameters is very useful. Could we see something on proper session management in the future?

Anonymous's picture

Re: _POST

On January 9th, 2003 Anonymous says:

great heads up... i'll will look into this futher...

thankx!

Anonymous's picture

Re: Security with PHP Superglobals

On January 7th, 2003 Anonymous says:

Nice article. With regard to SSL and GET vs. POST. Form data sent with GET will be encrypted on the wire with SSL, even though it will be visible in your browser's Address field. POST is nice because it won't show sensitive or ugly data in the Address field. But as far as on the wire encryption with SSL goes, there is no difference.

Anonymous's picture

hey dumb ass who ever coded t

On July 14th, 2005 Anonymous (not verified) says:

hey dumb ass who ever coded this page, you let the damn margin go wild.
stupid f***ing idiot!

Yeah's picture

Yeah what a retard.

On November 26th, 2005 Yeah (not verified) says:

Yeah what a retard.

Anonymous's picture

ya no kidding..

On July 14th, 2005 Anonymous (not verified) says:

ya no kidding..

Post new comment

Please note that comments may not appear immediately, so there is no need to repost your comment.
The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <pre> <ul> <ol> <li> <dl> <dt> <dd> <i> <b>
  • Lines and paragraphs break automatically.

More information about formatting options

Newsletter

Each week Linux Journal editors will tell you what's hot in the world of Linux. You will receive late breaking news, technical tips and tricks, and links to in-depth stories featured on www.linuxjournal.com.
Sign up for our Email Newsletter

Tech Tip Videos

From the Magazine

July 2009, #183

News Flash: Linux Kernel 3.0 to include an on-the-go Expresso machine interface! Ok, maybe not, but Linux is definitely going mobile, from phones to e-readers. Find out more inside about Android, the Kindle 2, the Western Digital MyBook II, The Bug, and Indamixx (a portable recording studio). And if you've gone mobile and you been wanting more Emacs in your life then check out Conkeror.


To compliment the mobile we've got the stationary: parsing command line options with getopt, checking your Ruby code with metric_fu, and building a secure Squid proxy. How is this stationary you ask? What can we say? It's not. We just wanted to see if anybody actually read this part of the page :) .


All this and more, and all you have to do is get your hot sweaty hands on the latest copy of Linux Journal.





Read this issue