Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Validating contents of $_GET

Posted on 2013-01-23
11
Medium Priority
?
356 Views
Last Modified: 2013-02-13
I am looking for a way to validate the contents of $_GET and/or $_POST, something along the lines of PHP is_uploaded_file() works.  Here is the specific scenario.

Two programmers are working on different classes as part of a larger web site.  The "bad" programmer intends to sabotage the project by changing the request variable with something like this, before handing off control to the class coded by the good programmer.

$_GET['username'] = 'Evil';

Since $_GET is mutable and present in every class and namespace, this risk exists.  Is there a way to verify the original request variable, other than to trust $_GET?

Thanks to all, ~Ray
0
Comment
Question by:Ray Paseur
  • 4
  • 2
  • 2
  • +2
11 Comments
 
LVL 35

Accepted Solution

by:
gr8gonzo earned 2000 total points
ID: 38811856
Hi Ray,

That's going to be difficult to control, since a malicious programmer will typically have ways to gain access to just about every part of the code (if not directly, then via PHP's own permissions).

However, you can probably make it more difficult by using a custom class to take control over the values, and then only allow for data retrieval and no modification. For example, let's say you use auto_prepend_file to include a file called SafeRequest.class.php:

<?php

// Run the init() routine before anything else can modify $_GET.
SafeRequest::init();

class SafeRequest
{
  private static $data = null;
  private static $instances = 0;

  public static function init()
  {
    // Don't allow multiple init()s to run!
    if(self::$instances == 0)
    {
      global $_GET, $_POST;
      self::$data = array($_GET,$_POST);
      self::$instances = 1;
    }
  }

  private static function getData($type,$var,$default)
  {
    if(isset(self::$data[$type][$var]))
    {
       return self::$data[$type][$var];
    }
    else
    {
       return $default;
    }
  }

  public static function Get($var,$default = null)
  {
    return self::getData(0,$var,$default);
  }

  public static function Post($var,$default = null)
  {
    return self::getData(1,$var,$default);
  }
  
}

?>

Open in new window


Then instead of something like:

$username = $_GET["username"];

you would use it like:

$username = SafeRequest::Get("username");
0
 
LVL 35

Assisted Solution

by:gr8gonzo
gr8gonzo earned 2000 total points
ID: 38811870
Also bear in mind that this means that you would double the amount of memory used by GET and POST for each request. It might be wise to even clear out $_GET and $_POST in the init() routine:

$_GET = array();
$_POST = array();

...to help enforce programmers to use SafeRequest and to reduce the memory footprint.

You'd have to keep SafeRequest write / mod perms locked down so that the auto_prepend_file would only be able to be read by PHP and other potential malicious sources.
0
 
LVL 34

Expert Comment

by:Slick812
ID: 38811922
greetings   Ray_Paseur, , ,  There are ways to get the PHP page URI query string that are not using the $_GET array, please look on manual at -
http://php.net/manual/en/reserved.variables.server.php

you might should try the -
$uri = $_SERVER['REQUEST_URI'];
or
$qs = $_SERVER['QUERY_STRING'];

but these are the NON parsed and separated strings, so you will have to separate out any string info in them. I do not believe that you can change these with -
$_SERVER['QUERY_STRING'] = '?user=evil&cost=none';
but I have not tried to do that.

Oh and if it's a file upload or LONG post, then this query string can be alot of text to parse.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 31

Expert Comment

by:Marco Gasi
ID: 38811965
Hi Ray,
hi gr8gonzo,
I apologize if I post here a comment: I'm not so presumptuous to think to can give some answer here, but it seems an ideal job for a bootstrap file: if all requests are intercepted by one file, something like what happens in MVC pattern, there you can operate all dirty job about securing and validating data. Am I wrong?
0
 
LVL 35

Expert Comment

by:gr8gonzo
ID: 38812047
Hi marqusG,

That is what I was suggesting. The auto_prepend_file directive means that the specific script will be automatically included with every request.
0
 
LVL 84

Expert Comment

by:Dave Baldwin
ID: 38812293
On both Apache and IIS, $_SERVER['REQUEST_URI'] contains the file name and the query string like "/index.php?qstr=99" and should be unaffected by changing the $_GET values.  You can parse that to get the original value sent to the server.  Explode at '?' first and then explode the second part at '&' to get the individual name/value pairs.
0
 
LVL 35

Expert Comment

by:gr8gonzo
ID: 38813961
Dave and Slick,

I see two problems with the approach of checking against REQUEST_URI:

1. To validate GET against REQUEST_URI means parsing REQUEST_URI anytime you want to validate something, which can have an impact on performance (assuming the application is large enough to allow malicious code to go unseen, there are probably many instances that would need this).

2. REQUEST_URI is editable. A malicious user could also change the REQUEST_URI fairly easily if they were trying hard enough to cover their tracks. The same applies to all environment variables, really. The only way for a malicious user not to be able to completely clear their tracks is if there were a signature applied at the web server level prior to the request entering the PHP engine. However, PHP would need to be able to validate the signature, which usually means that unless it's a secured method that can't be reverse engineered, a malicious user could probably just recreate the signature after the injection.
0
 
LVL 34

Expert Comment

by:Slick812
ID: 38815913
not sure that  Ray_Paseur is even reading this comment train, but, , , I do agree wid  gr8gonzo, as I tested the $_SERVER['REQUEST_URI'] , you can after all change it by assignment wid =
it is also limited to only the GET as the URI would indicate.  I tried the php function  apache_request_headers()  but it was not enabled on that particular server.
I do not see the parse of a string as being much of a drawback, at least for me, do it quite alot.
But I have been in development teams, and I really can not see how having a team coder, purposefully sabotage a teams work, be something that does not demand the entire attention of the whole Web site personnel , coders, owners, sponsors, to fix that problem, not just have a GET entry validation.

I am also suprized that I can not get the raw request headers for a POST in PHP, before they are placed on the $_POST array, I tried several things, and web searched it, except for the apache_request_headers()  I found no valid examples, , LOL guess I too dumb to find it, LOL
0
 
LVL 84

Expert Comment

by:Dave Baldwin
ID: 38815950
You can get 'ALL_HTTP' in IIS but not Apache.  $_SERVER['REQUEST_URI'] and $_GET come from the same place (passed from the web server) so there is no difference in the ability to edit them at the source.  Ray asked for some way to check $_GET and that is the only thing I see that corresponds to the $_GET array.

I agree with Slick812 that having a person on the team that sabotages the code that the others use is a Real Problem.  Worthy of a first class beat-down.
0
 
LVL 111

Author Closing Comment

by:Ray Paseur
ID: 38885603
I've chewed this question fairly well and the cud is that auto_prepend is probably the best solution.  Too bad that PHP made all the SuperGlobal variables mutable.  I'll post a code sample showing how lame that is!  And I agree with all the comments about what a problem it would be to have a rogue programmer on the team!

Thanks, colleagues.  Thoughtful contributions all around, ~Ray
0
 
LVL 111

Author Comment

by:Ray Paseur
ID: 38885610
A test case...

<?php // get.php 
error_reporting(E_ALL);

// LOOKING FOR A WAY TO TELL IF GET HAS BEEN TAMPERED WITH...
// TEST WITH ?foo=bar
// TEST WITH ?a=b

// THIS SHOULD SET $_get EQUAL TO $_GET
parse_str($_SERVER["QUERY_STRING"], $_get);

// AND IT DOES
if ($_GET == $_get) echo ' == ';
if ($_GET === $_get) echo ' === ';
var_dump($_GET, $_get);

// MUNG $_GET AND TEST
$_GET['foo'] = 'bar';
if ($_GET == $_get) echo ' == ';
if ($_GET === $_get) echo ' === ';
var_dump($_GET, $_get);

// BUT ALAS, $_SERVER IS NOT IMMUTABLE, EVEN THOUGH IT SHOULD BE READ-ONLY
$_SERVER['QUERY_STRING'] = 'WHACKED';
phpinfo();

Open in new window

0

Featured Post

Nothing ever in the clear!

This technical paper will help you implement VMware’s VM encryption as well as implement Veeam encryption which together will achieve the nothing ever in the clear goal. If a bad guy steals VMs, backups or traffic they get nothing.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When it comes to write a Context Sensitive Help (an online help that is obtained from a specific point in state of software to provide help with that state) ,  first we need to make the file that contains all topics, which are given exclusive IDs. …
There are times when I have encountered the need to decompress a response from a PHP request. This is how it's done, but you must have control of the request and you can set the Accept-Encoding header.
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The is a quite short video tutorial. In this video, I'm going to show you how to create self-host WordPress blog with free hosting service.
Suggested Courses
Course of the Month10 days, 12 hours left to enroll

885 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question