How to make GET safe

Don’t forget to make sure register_globals is off. Otherwise, you’ll need to take more thorough steps to ensure extra data isn’t being inputted. Then just simply validate the input that’s coming in.

On the same topic, check Strategy Pattern implementation on input validation.

If you’re interesed in security issues of user input, check this video. It is long and a little bit boring but it pretty much covers the basic security hazards.

Two things to always keep in mind:

  • Validate user input
  • Validate application output

No. Bad. Entirely wrong approach to security.

Simply assume that all incoming data is dangerous in some way or other. You don’t know how it is dangerous, because a) it’s impossible to know every known security threat out there, and b) there’s always unknown threats lurking just outside of view.

Any time you have incoming data, you have an idea of what it is. If you’re expecting a user ID, for example, make sure it fits your predefined criteria of user IDs (usually positive integers) and validate against that. For each and every incoming piece of data, go through this same routine: What should it be? How would I verify that it is what it should be? How do I gracefully reject “bad” data?

Never approach it with the idea of trying to identify all possible threats and securing against them - you will fail, that is 120% guaranteed.

If you want an idea of how bad things can get, Google “sql injection” and “cross-site scripting” (aka XSS), that’ll give you an idea. Things like your entire database being shown to an attacker, or an attacker uploading some fun little script that surreptitiously captures all your users’ usernames and passwords. Things like that. Bad things. Bad things that you don’t want to happen.

I’m currently in the process of hardening an application that was written from the viewpoint of, “These are the attacks I know about, so I’ll make sure they can’t happen.” It’s one of the weakest apps I’ve ever seen (from a security standpoint) because of it - within minutes of opening just the first file (which is written in ASP, and I’m a PHP programmer) I’d identified more than half a dozen different ways to successfully attack it. It’s atrocious, and it’s because the guy who wrote it didn’t have the right mindset about security.

So get it out of your head right now that you should be hardening your apps against particular threats, because a) you’ll miss threats that are out there, and b) new threats that you couldn’t possibly know about (because no one did) will appear. There is no silver bullet that will guarantee a secure app, but validating every piece of incoming data is a huge step in the right direction and will stop attacks you never thought of.

yes wwb_99 , sure no one need to initiaite actions this is for example sometimes you need to use GET specially in CMS,

then as I told in one of my replies that The POST or GET are same who can send malicious code with GET can send it with POST you can write simplae PHP script or AJAX script to send malicious code using POST method that idea don’t trust the data that coming from user or out of your system border
look to this AJAX call you can simply send POST request


 var objHTTP, strResult;
  objHTTP = new ActiveXObject('Microsoft.XMLHTTP');
  objHTTP.Open('POST',"mypage.php",false);
  objHTTP.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');

  objHTTP.send("action="+malicious code);

  strResult=objHTTP.responseText;



nice links thank you buth links are good

thanks

[b]kromey

[/b]thank you for the post i know thats the way it should be i just wanted few examples

There are many things that can be done to secure an app. It should start with only using GET and POST to pass trivial bits of info that will be used to perform an action. But even then the data passed needs to be validated, verified, and tested.
If you are expecting an integer, test for it when fetching the result.

if (isset(intval($_GET['out'])))

If you are expecting a string, you should verify that you are receiving a valid string according to what should be coming in.

if ($functionType == "display")

If you are using the result in queries you should addslashes, after validating.

$type = addslashes($_GET['type']);

yes wwb_99 , sure no one need to initiaite actions this is for example sometimes you need to use GET specially in CMS,

The point is not about malicious stuff. It is about non-malicious stuff accidentally doing malicious things because a developer does something dumb with HTTP. I would also add that manipulating GET requests is alot easier than futzing with POST because it just requires a browser without any special technical knowlege or utilities.

If you are using the result in queries you should addslashes, after validating.

Don’t use addslashes. Ever. Use a proper database escape function. Just about all the php database libraries have one.

Or, better yet, use parameters and bind them in a strongly typed manner.

I use a white-list approach whenever possible…no matter where the data comes from. This can be done with very few lines, depending on your comfort level with PHP. Here’s four examples of doing the same thing with exceedingly less code. Keep in mind that each of the 4 snips below does the same thing. If you spot any errors, let me know … each method is E_ALL-friendly. :slight_smile:

Scenario: A user passes a variable to your script via the URL and you need to ensure that the value submitted is valid and allowable. In this case, we’ll assume that values of “yes”, “no” and “maybe” will be valid values, while any other values should simply be discarded as though they never existed.

More Verbose - 10 lines:

<?php
    // URL parameter variable initialized to false.
    $url_var = false;

    // Check if variable was passed via URL...
    if (isset($_GET['url_var'])) {
        // ...and re-assign initiailized variable whenever needed.
        $url_var = $_GET['url_var'];
    }

    // Reaction if there's a URL passed variable...
    if ($url_var) {
        // ...get an array of valid (expected) values; the white-list...
        $ok_vars = array('yes', 'no', 'maybe');
        // ...and check if variable does not match an allowed value...
        if (!in_array($url_var, $ok_vars)) {
            // ...and if not, ditch the variable.
            $url_var = false;
        }
    }
?>

Less Verbose - 7 lines:

<?php
    // Get the URL variable or default it to false.
    $url_var = (isset($_GET['url_var'])) ? $_GET['url_var'] : false;

    // Setup an array of valid (expected) values; the white-list.
    $ok_vars = array('yes', 'no', 'maybe');

    // Reaction to the URL passed variable...
    if ($url_var) {
        // Check if passed parameter does not match an allowed value...
        if (!in_array($url_var, $ok_vars)) {
            // ...and if not, ditch the variable.
            $url_var = false;
        }
    }
?>

Pretty Hardcore - 4 lines:

<?php
    // Get the URL variable or default it to false.
    $url_var = (isset($_GET['url_var'])) ? $_GET['url_var'] : false;
    // Reaction if there's a URL passed variable...
    if ($url_var)
        // ...check if variable does not match an allowed value...
        if (!in_array($url_var, array('yes', 'no', 'maybe')))
            // ...and if not, ditch the variable.
            $url_var = false;
?>

Totally Anal - 1 Line:

<?php
    // Check if the URL var is present, and if so, validate it against allowable values or ditch it.
    if (isset($_GET['url_var'])) $url_var = (!in_array($_GET['url_var'], array('yes', 'no', 'maybe'))) ? false : $_GET['url_var'];
?>

Take note to NOT use the $_GET variable in subsequent code as it is not clean; only the $url_var is cleaned (rather, accepted or trashed). You could additionally unset the $_GET variable after having grabbed it, to ensure that it cannot be further used within your code.

In all the examples above, note that the second parameter in the is_array() function is an array of the white-list values that your script will accept for $url_var. In the third and fourth examples above, since the white-list was fairly short, I wrote the array directly in as the second paramater of the is_array() function. While this is perfectly “legal” it can become an onscreen mess easily. To avoid the onscreen clutter, typically you’ll assign your white-list array to a single variable and then use that as the second parameter instead (as shown in the first and second examples above).

Best,

  • Cranjled

I’ve been using is_numeric(). Now because it wasn’t mentioned I’m worried that there might be something wrong with it… is there?

is_numeric() … is fine to use when you’re expecting a number that’s either postive, negative, decimal, or even zero. In all these cases, you’ll get a TRUE. A zero returning TRUE sometimes throws people off, but a 0 is in fact numeric. There’s a couple of gotchas though…(well, after you get the hang of 'em, they’re actually ‘features’)…

First gotcha is that is_numeric() will return TRUE when it’s passed an exponential number such as +0123.45e6 even though the number has a letter in it.

Second gotcha is that hexadecimal values will also return as TRUE so long as they do not contain a sign, decimal or exponent; for example, a value of 0xFF returns TRUE.

ctype_digit() … will return TRUE only if the value passed consists only of numbers. A decimal or negatively signed number will cause a FALSE. …again, the gotcha/feature paradox… but perfectly logical upon consideration.

intval() … I think this might produce unexpected results, depending on the value passed. I haven’t really tried it out…

…and along the vein of PHP types…

Check out this sweet Type Comparison Chart…a must bookmark!

Hope that helps,

  • Cranjled

I always sanitize the user input, whether it’s from GET or POST.
http://www.owasp.org/index.php/OWASP_PHP_Filters

Tried and tested methods, can easily be combined with more sanity :wink:

In fact, just visit http://www.owasp.org/
and start reading :slight_smile:

Good point…! Of course all user input is malicious and should be validated. I wasn’t meaning to imply that sanitizing just $_GET was good enough…it’s just what the main theme of the thread was…

:wink:

Thanks for the link,

  • Cranjled
<?php

function clean($var) { ... }
foreach ($_GET as $key => $value) $GET[$key] = clean($value);

?>

edit: Just saw: http://www.sitepoint.com/forums/showpost.php?p=3045163&postcount=30

I tried editing $_GET and other similar values directly before and I think it didn’t work… does it? :x

You should always use error checking for your $_GET variables. It could be something as simple as this:

$variable = $_GET[‘variable’];

if($variable==‘category1’){
echo “<p>some text</p>”;
}
else{
echo “<p>You broke the Internet.</p>”;
}

or, you could use ereg and eregi expressions to check if the variable contains only text

just visit http://books.gzthai.com
and start download and reading

The simple test below proves that you can edit a $_GET variable directly.

    // Getting the 'raw' GET variable.
    $bad_get = $_GET['var'];
    echo "<p>$bad_get</p>";

    // Resetting the GET variable within the script.
    $_GET['var'] = 'this';

    // The end result.
    echo '<pre>';
    print_r($_GET);
    echo '</pre>';

However, doing this is a bad idea; it can lead to complacency. It’s best to get the data from $_GET where you can then fully process/inspect it…and only ever use /your/ re-assigned variables…and never the direct $_GETs.

After you get the data from the $_GET variable, trash it to make sure no holes can be introduced in this way.

At least, that’s how I do it!

:slight_smile:

PHP’s “Character Type Functions” are very specific, fast, and much easier to use than reg expressions. To date, there are 11 such functions listed in the PHP Manual, most of which return either true or false. Instead of an elaborate pattern comparison as with the reg functions, each ctype function has it’s own very specific tasks.

For example to test a variable for “only text” as you’d mentioned in your post, all you need is:

$is_alpha = ctype_alpha($var);
// $is_alpha will be TRUE if only letters in $var; FALSE otherwise.

Or, if you wanted to allow numbers and letters,

$is_alnum = ctype_alnum($var);
// $is_alnum will be TRUE if $var contains only numbers and letters; FALSE otherwise.

Of course, you could also put these functions into conditionals like:

if(!ctype_alpha($var)) {
    // More than letters were submitted; do somethin about it!
}

Check them out … those functions have saved me much work … and code!

i have GET var that accepts either ‘a’ or < > = but that < and > or = is passed as special character in addressbar may be hex charaacters…%3D% etc
so how to validate it
any function example

Frank1 … how’s that? Can you explain this again…sorry, I don’t get it.

And, why would you pass ‘<’ or ‘>’ through the URL? My feeling on this is that it should be avoided, though I’m certainly no expert. Is there another way you can achieve this?

Maybe I understood you wrong…

why is it bad idea?
well i am doing like this
its search or search with drop down navigation…part of it

echo '<tr><td align="right">Price</td>
  <td align="left">
  <select name="opr">
  <option value="any">All</option>

  <option value="=">Equal to</option>>
  <option value=">=">Greater than</option></option>
  <option value="<=">Less than</option> </option>
  </select>&nbsp
  </select>&nbsp</td></tr>';
    echo '<tr><td align="right">Price </td>
	<td align="left"><input type="text" name="cid" size="15" maxlength="25" />&nbsp;</td></tr>';
       echo '<tr><td align="right">Property Type</td>
	   <td align="left">
	<select name="pfor">
  <option value="1">Sale</option>

and i next page i do…

		}
							else //opreator is not all
						{
						
						 $prop_for = ( $pfor == 1 ) ? 'sale' : 'hire';
										$query .= ' and property_for like \\'' . $prop_for . '\\' and price ' . $opr . ' ' . $var;
						
						}

that way i am not having to write query for > ,<= and = separately.
but i am not getting exact way of validating that variable “opr”…
any suggestion…
by the way well / ’ " avoided so that people do not url or sql inject but can sql or url injection can be done through <, >, =
(i am not trying to accept specail charaters just <,> and =…only)