• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 357
  • Last Modified:

Validating contents of $_GET

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
Ray Paseur
Asked:
Ray Paseur
  • 4
  • 2
  • 2
  • +2
2 Solutions
 
gr8gonzoConsultantCommented:
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
 
gr8gonzoConsultantCommented:
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
 
Slick812Commented:
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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
Marco GasiFreelancerCommented:
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
 
gr8gonzoConsultantCommented:
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
 
Dave BaldwinFixer of ProblemsCommented:
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
 
gr8gonzoConsultantCommented:
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
 
Slick812Commented:
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
 
Dave BaldwinFixer of ProblemsCommented:
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
 
Ray PaseurAuthor Commented:
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
 
Ray PaseurAuthor Commented:
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

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

  • 4
  • 2
  • 2
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now