Faking a post variable......is it possible?

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

malcolmboston
DevNet Resident
Posts: 1826
Joined: Tue Nov 18, 2003 1:09 pm
Location: Middlesbrough, UK

Faking a post variable......is it possible?

Post by malcolmboston »

Its not for my use, but rather defending my application.

is there anyway (even if its not perfectly feasible) for an EU to fake a post variable?
User avatar
R4000
Forum Contributor
Posts: 168
Joined: Wed Mar 08, 2006 12:50 pm
Location: Cambridge, United Kingdom

Post by R4000 »

yup it is possible, but you have to use sockets ect. and build your own fake http client as such.

Open socket, send headers (not hard to work out), ignore all output untill a blank newline (unless you want to parse return headers), then print everything after..
malcolmboston
DevNet Resident
Posts: 1826
Joined: Tue Nov 18, 2003 1:09 pm
Location: Middlesbrough, UK

Post by malcolmboston »

how is it stopped?
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post by Maugrim_The_Reaper »

You can try to force the user to use your own forms.

To be honest your application should not care how a user chooses to send input. So long as it filtered effectively they can fake all the POST requests they want... As a quick rule - if a URI on your app does not expect any POST data, then your input filter should simply discard any such data immediately.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Maugrim_The_Reaper wrote:You can try to force the user to use your own forms.

To be honest your application should not care how a user chooses to send input. So long as it filtered effectively they can fake all the POST requests they want... As a quick rule - if a URI on your app does not expect any POST data, then your input filter should simply discard any such data immediately.
You can also write a function that collects post data into variables for you, in the expected formats. You tell it at the start of the script you're expecting 'foo' from POST and that it should be an integer. If it's not an integer it gets dropped. This is also a great way to prevent SQL injection.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Here's a little class I just made up that would do some filtering of data coming in from any of the superglobals.

Bear in mind that POST and GET send strings almost all the time so a '42' wouldn't validate as is_int() but rather is_numeric(). The use of the PCRE match will be a big help.

If any of the expected variables are not found they are nulled, if they don't satisfy the level of sanity you set they are nulled, if they look ok, they are stored.

Code: Select all

<?php

/*
 A basic class for sanitizing data being received over HTTP
   in PHP Super Globals.

 Author: d11wtq (Chris Corbyn)
 Date: 2006-04-19

 License: none.. Just use it
 
 */

class htDataHandler
{

	private
	
	$htVars = array(),
	$expectVars = array(), //Variable names
	$expectLocs = array(), //POST, GET, COOKIE, REQUEST, SESSION
	$expectTypes = array(), //Data types
	$expectMatches = array(); //PCRE
	
	public function __construct()
	{
		//
	}

	public function expectData($array)
	{
		foreach ($array as $k => $a)
		{
			if (is_array($a) && sizeof($a) >= 2)
			{
				$params = array_values($a);
				$this->addVar($params, $k);
				$this->addLoc($params, $k);
				$this->addMatch($params, $k);
				$this->addType($params, $k);
			}
		}
		$this->validate();
	}

	public function getVar($v)
	{
		if (isset($this->htVars[$v])) return $this->htVars[$v];
	}

	private function validate()
	{
		foreach ($this->expectVars as $k => $v)
		{
			//It seems this is needed for variable variable in the superglobal scope
			global ${$this->expectLocs[$k]};
			
			if (isset(${$this->expectLocs[$k]}[$v]))
			{
				$tmp = ${$this->expectLocs[$k]}[$v]; //Read it but don't use it yet
				
				if ($this->expectTypes[$k] && !$this->checkType($tmp, $this->expectTypes[$k])) $tmp = null;
				if ($this->expectMatches[$k] && !$this->checkMatch($tmp, $this->expectMatches[$k])) $tmp = null;
				
				$this->htVars[$v] = $tmp;
			}
			else $this->htVars[$v] = null;
		}
	}

	private function checkType($v, $type)
	{
		switch (strtolower($type))
		{
			case 'str':
			case 'string': return is_string($v);
			case 'int':
			case 'integer': return is_int($v);
			case 'float': return is_float($v);
			case 'double': return is_double($v);
			case 'array': return is_array($v);
			case 'object': return is_object($v);
			case 'numeric': return is_numeric($v);
		}
		return false;
	}

	private function checkMatch($v, $pattern)
	{
		if (preg_match($pattern, $v)) return true;
		else return false;
	}

	private function addVar($a, $k)
	{
		if (isset($a[0])) $this->expectVars[$k] = $a[0];
		else $this->expectVars[$k] = null;
	}

	private function addType($a, $k)
	{
		if (isset($a[1])) $this->expectTypes[$k] = $a[1];
		else $this->expectTypes[$k] = null;
	}

	private function addMatch($a, $k)
	{
		if (!empty($a[2])) $this->expectMatches[$k] = $a[2];
		else $this->expectMatches[$k] = null;
	}

	private function addLoc($a, $k)
	{
		if (!empty($a[3])) $this->expectLocs[$k] = $this->getLocation($a[3]);
		else $this->expectLocs[$k] = $this->getLocation(0);
	}

	private function getLocation($loc)
	{
		switch (strtolower($loc))
		{
			case 'get':
			case '$_get':
			case '_get': return '_GET';
			//
			case 'post':
			case '$_post':
			case '_post': return '_POST';
			//
			case 'cookie':
			case '$_cookie':
			case '_cookie': return '_COOKIE';
			//
			case 'session':
			case '$_session':
			case '_session': return '_SESSION';
			//
			case 'request':
			case '$_request':
			case '_request':
			default: return '_REQUEST';
		}
	}

}

?>

Code: Select all

/*
 array (
	array( string varName, string varType [, string match [, string requestLocation] ] )
 )
 */
$a = array(
	array('foo', 'string', '/^foo\d{2}$/i', 'get'),
	array('bar', 'numeric')
);

$handler = new htDataHandler;

$handler->expectData($a);

echo $handler->getVar('foo');
echo $handler->getVar('bar');
EDIT | Changed isset() to !empty() for the optional params.
Last edited by Chris Corbyn on Wed Apr 19, 2006 12:54 pm, edited 1 time in total.
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

Shiftlett some input on the matter

viewtopic.php?p=252019#252019


Hey Chris, going a bit off topic here, but instead only nulling the invalid values, perhaps check them in a garbage variables, which can be access via $this->_getRaw() or something..
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Jcart wrote:Shiftlett some input on the matter

viewtopic.php?p=252019#252019


Hey Chris, going a bit off topic here, but instead only nulling the invalid values, perhaps check them in a garbage variables, which can be access via $this->_getRaw() or something..
Yeah I guess you could do that. I just knocked it up as a rough example.

Part of the reason it's done like that is so that the logic reads nicely when checking it was validated ok.

Code: Select all

if ($obj->getVar('foo') !== null) echo $obj->getVar('foo');
I guess there's always the chance that you wanted it to be null though.... but if that's the case you'd know before hand. The basic idea of filtering is still the same however.
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

I meant you do assign them null, but before you do

Code: Select all

$this->raw['variable'] = $variable;

// if is invalid
$variable = null;
then

Code: Select all

public function getRaw($key) {
   return $this->raw[$key];
}
This would be useful for error reporting and such, although I usually do throw my getRaw functions through some sort of minimal filtering to prevent XSS attacks and such aswell

Talk to you on msn about this furtur, as we (or I :P) sorta have hijacked the thread :P
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Jcart wrote:I meant you do assign them null, but before you do

Code: Select all

$this->raw['variable'] = $variable;

// if is invalid
$variable = null;
then

Code: Select all

public function getRaw($key) {
   return $this->raw[$key];
}
This would be useful for error reporting and such, although I usually do throw my getRaw functions through some sort of minimal filtering to prevent XSS attacks and such aswell

Talk to you on msn about this furtur, as we (or I :P) sorta have hijacked the thread :P
Ah gotcha. Good point since if the data didn't validate you may still want to use it but do soemthing else with it.

/me steers thread back on topic
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

R4000 wrote:yup it is possible, but you have to use sockets ect. and build your own fake http client as such.

Open socket, send headers (not hard to work out), ignore all output untill a blank newline (unless you want to parse return headers), then print everything after..
No, you don't have to.

There are plugins for Firefox that allow you to modify forms realtime, there are proxies that let you do so, and more.

It is trivial - not nearly as complicated as you are implying it to be.
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

you can easily send post headers in a couple lines of code.. cURL
alvinphp
Forum Contributor
Posts: 380
Joined: Wed Sep 21, 2005 11:47 am

Post by alvinphp »

Your application should validate all the data on the server side to make sure the data is what it should be (ie accessory methods). Then you should not need to worry about a fake post. One of the weakness of javascript is since the validation is done on the client it can be bypassed and then a person could theoretically inject harmful code that could mess up your form/site/application.
User avatar
a94060
Forum Regular
Posts: 543
Joined: Fri Feb 10, 2006 4:53 pm

Post by a94060 »

could you possibly check the URl that the data is coming from? use like a strpos or something?
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post by alex.barylski »

a94060 wrote:could you possibly check the URl that the data is coming from? use like a strpos or something?
Most anything you would use to uniquely indentify a user is most likley easily spoofed...

You have no choice but to sanitize data...

You could possibly make sure that data was sent by a unique person as opposed to abot of some sort by using CAPTCHA, which would require human intervention...

But that POST could have come from anywhere, including there own web site, etc...allowing them to spoof all the headers they want...
Post Reply