Jump to content
MakeWebGames

Security Question


BeastTheKidd

Recommended Posts

This is not for any specific game, or web development. This is simply a question for Security in PHP generally. Can anyone help me refresh my memory on the best security techniques that can be used.

Say I want to prevent XSS from a single form: would htmlentities on the certain variable on the way to the database as well as a mysql escape be sufficent enough to protect from XSS on that single input, or rather I use more functions? I heard it is better to escape and filter on input and escape output.

Say I want to make sure a variable contains only numbers, or certain values. Would it be sufficent to use abs(@intval($var)) to make sure its a number, or is more needed? Also, say i want the variable ( in this case $_GET ) to only contain 3 possible values (red, green, blue ).. Would this work?

 

$_GET['var'] = ( isset($_GET['var']) && in_array($_GET['var'],array('red','blue','green') ) : 'Do Something'; ? exit;

// I know this isnt completely right so thats why im asking.

 

Are their anymore security tips I should know about? Thanks,

-Dillion

Link to comment
Share on other sites

Well, even though security is a complex field, it's good to keep it as simple as possible.

XSS is one of the easiest things to secure a website from, but the techniques that you mention are lengthy and not needed at all.

You say you only want to allow integers? Yet, you are attempting to convert mixed data types to integers.

If you only want to ALLOW integers from input into processing, I'd suggest you filter out the rest of the data types. I prefer pattern matching.

Here's a simple Regex pattern that only allows for integers(note that it does NOT allow for floats):

^[0-9]$

An implementation of regex matching into a standard PHP web-form:

<?php

if (!empty($_POST['submit'])) {
   $error = array();
   if (empty($_POST['data'])) $error[] = 'Fill in all fields';
   elseif (count(preg_match('^[0-9]$', $_POST['data'], $matches)) <= 1) $error[] = 'Invalid data type';
   else {
       $data = $matches[0]; // valid data, integer
       { ... use data ... }
}

?>

The problem is with you methods is that although it is secure, it's neither optimized or usable. A user may just accidentally type a character, and their input is nullified to 1(any string converted to int equals 1).

Edited by Spudinski
Link to comment
Share on other sites

Yeah I understand Regex, I've actually used it a couple times before.. Very good. My question though is isn't it better to use native php functions or create a group of functons like these in an Object class, for reuse. ?

Is it better to use native PHP functions? No, Regex is much more powerful than any of those functions mentioned.

What you can do however, is prepare functions that switches between the data type you want to filter. Which you can then implement as an abstract class, and only use when needed.

Native PHP functions, like htmlentities(), are good, but they don't offer much flexibility towards what you want to filter.

Link to comment
Share on other sites

Your logic has a major flaw, I am afraid, which is programmer knowledge.

Yes, RegEx can be powerful, but that is assuming the programmer in question has a firm enough understanding to grasp what they are trying to make it do.

Take a simple alpha-numeric value check for example, with a character minimum of 4 and maximum of 12, with lower and upper case characters allowed.

For someone with no idea of RegEx, I would rather advise them to use something like ctype_alnum($var) than preg_match("`[0-9a-z]{4,12}`i", $var)

I'm sorry, but that statement makes no sense to me.

Once a programmer knows how to use Regex, they can take that knowledge and apply it mostly anywhere.

Also, it's much quicker.

On a system's standpoint, I can find a single string in a thousand files in an instant.

On a developers standpoint, I can limit, reform and validate any datatype with less than three lines of code.

Link to comment
Share on other sites

ctype_xxx() functions are generally considered to be faster than

preg_xxx() functions for a number of reasons, not least in which the

low startup costs and table lookup.

Consider the following generator and tests:

<?php
/**
 * gen.php
 **/
for ($i = 0; $i < 100000000; $i++)
{
   $data = base64_encode(sha1(mt_rand(), true));

   if (mt_rand(0, 1))
       $data = strtolower($data);
   else
       $data = strtoupper($data);

   echo substr($data, 0, mt_rand(2, 28)) . "\n";
}
<?php
/**
 * test1.php : Using ctype_alnum() and strlen()
 **/
$handle = fopen('input.txt', 'r');

while ($line = fgets($handle))
{
   $line = trim($line);

   if (ctype_alnum($line))
   {
       $len = strlen($line);

       if (($len >= 4) && ($len <= 12))
       {
           echo $line . "\n";
       }
   }
}

fclose($handle);
<?php
/**
 * test2.php : Using preg_match()
 **/
$handle = fopen('input.txt', 'r');

while ($line = fgets($handle))
{
   $line = trim($line);

   if (preg_match('`^[A-Za-z0-9]{4,12}$`', $line))
   {
       echo $line . "\n";
   }
}

fclose($handle);
<?php
/**
 * test3.php : Using strlen() and ctype_alnum()
 **/
$handle = fopen('input.txt', 'r');

while ($line = fgets($handle))
{
   $line = trim($line);
   $len  = strlen($line);

   if (($len >= 4) && ($len <= 12))
   {
       if (ctype_alnum($line))
       {
           echo $line . "\n";
       }
   }
}

fclose($handle);
<?php
/**
 * test4.php : Using preg_match() with case insensitivity
 **/
$handle = fopen('input.txt', 'r');

while ($line = fgets($handle))
{
   $line = trim($line);

   if (preg_match('`^[A-Z0-9]{4,12}$`i', $line))
   {
       echo $line . "\n";
   }
}

fclose($handle);

Results

$ php -f gen.txt > input.txt

$ time php -f test1.php > output.txt
real  0m22.655s
user  0m16.712s
sys   0m5.706s

$ time php -f test2.php > output.txt
real  0m29.806s
user  0m23.078s
sys   0m6.150s

$ time php -f test3.php > output.txt
real  0m22.750s
user  0m16.686s
sys   0m5.626s

$ time php -f test4.php > output.txt
real  0m32.519s
user  0m25.375s
sys   0m6.530s

Not surprisingly, ctype_alnum() beats preg_match() by a fair amount. I

agree that at command line level, searching for data is made simple by

regular expressions, they are indeed a useful tool to have at hand,

however in context, they are much slower.

I'd much rather use a couple of extra lines and perhaps the odd extra

if() statement over a single complex regex, but then I favor code

readability over SLOC.

For those wondering, the timings were performed on an old Athlon running

Linux with a couple of Gb of memory and running in single-user mode.

The actual results shown were the best of 3 runs for each test, and yes,

all tests did produce exactly the same output line count.

Mind using ereg on system level? Vs. PHP's ctype_x? PHP has made an implementation of regex into their application, and under PHP regex is not yet complete.

You are testing things that are beyond PHP intended capabilities of regex, you are filtering about a Gb of data.

If I could, I would suggest that you port the regex code to shell(ereg) for valid inquiry of actual regex results.

Link to comment
Share on other sites

I'm confused. Does it really matter which one I use, basically will it hit my performance that much? If its only a half a second or so I really don't mind. Also on the topic of optimizing queries... I know you can combine queries, but how so? Also, Does formatting increase the speed at all, or just make the database cleaner ( Basically, is it really needed or just mainly a preference? ). Thank you all for your help

Link to comment
Share on other sites

Back when i first started coding and was worried about security, i looked up everything i could and made a function in which you can clean a variable or an array and choose the way to clean it (sql, html, bbcode, etc). Anyway chances are alot of people have made this kind of thing.

A great way to get nothing but an integer is to do

$var=($var * 1);

if $var is not an integer it will return 0, the only drawback is if your dealing in negative numbers it will reverse the flow

Edited by runthis
Link to comment
Share on other sites

I was thinking of creating a function that could clean any variable or array, and having it able to select how to clean it too. However, how would one achieve such an outcome?

I could see it being something of this sort:

<?php

   public function validateInput($input,$method)
   {
       if(!empty($input) && !empty($method))
       {
            if($method == "mysql")
                return mysql_real_escape_string($input);
           if($method == "html")
               return htmlentities($html);
       }
       else
       {
           echo "Invalid input or no valid method was chosen.";
           exit;
       }
   }

?>

Link to comment
Share on other sites

Contrary to the post directly below this one, this is a fast and easy way to never have to worry about xss,sql injections. This is a common script and should be updated to suit your own needs. For instance in my version, several of the cases have been combined into one line and sql escape added to some of the cases

Use:

for integer = $var=sanitizeOne($var, 'int');

for query = $var=sanitizeOne($var, 'sql');

for nohtml = $var=sanitizeOne($var, 'nohtml');

for evenmore = $var=sanitizeOne($var, 'plain');

best security

$var=sanitizeOne($var, 'sql');

$var=sanitizeOne($var, 'plain');

 

 

function sanitizeOne($var, $type)

{       

       switch ( $type ) {

                       case 'int': // integer

                       $var = (int) $var;

                       break;



                       case 'str': // trim string

                       $var = trim ( $var );

                       break;



                       case 'nohtml': // trim string, no HTML allowed

                       $var = htmlentities ( trim ( $var ), ENT_QUOTES );

                       break;



                       case 'plain': // trim string, no HTML allowed, plain text

                       $var =  htmlentities ( trim ( $var ) , ENT_NOQUOTES )  ;

                       break;



                       case 'upper_word': // trim string, upper case words

                       $var = ucwords ( strtolower ( trim ( $var ) ) );

                       break;



                       case 'ucfirst': // trim string, upper case first word

                       $var = ucfirst ( strtolower ( trim ( $var ) ) );

                       break;



                       case 'lower': // trim string, lower case words

                       $var = strtolower ( trim ( $var ) );

                       break;



                       case 'urle': // trim string, url encoded

                       $var = urlencode ( trim ( $var ) );

                       break;



                       case 'trim_urle': // trim string, url decoded

                       $var = urldecode ( trim ( $var ) );

                       break;



                       case 'telephone': // True/False for a telephone number
                       $size = strlen ($var) ;
                       for ($x=0;$x<$size;$x++)
                       {
                               if ( ! ( ( ctype_digit($var[$x] ) || ($var[$x]=='+') || ($var[$x]=='*') || ($var[$x]=='p')) ) )
                               {
                                       return false
                               }
                       }
                       return true;
                       break;

                       case 'pin': // True/False for a PIN
                       if ( (strlen($var) != 13) || (ctype_digit($var)!=true) )
                       {
                               return false;
                       }
                       return true;
                       break;

                       case 'id_card': // True/False for an ID CARD
                       if ( (ctype_alpha( substr( $var , 0 , 2) ) != true ) || (ctype_digit( substr( $var , 2 , 6) ) != true ) || ( strlen($var) != 8))
                       {
                               return false;
                       }
                       return true;
                       break;

                       case 'sql': // True/False if the given string is SQL injection safe
                       //  insert code here, I usually use ADODB -> qstr() but depending on your needs you can use mysql_real_escape();
                       return mysql_real_escape_string($var);
                       break;
               }       
       return $var;
}
Edited by runthis
Link to comment
Share on other sites

we've seen many functions to try and secure their game easily, but none work, seemingly this one as well.

You are saying that everyone here secures variables one at a time?

That seems like an inefficient waste of time and space.

If i wanted to secure a single variable against all attacks, what would be your suggestion whilst still preserving the original text?

or

maybe you could show me your test in which the script i provided fails.

Link to comment
Share on other sites

If you are using your function for all variables, any item where you can input a number will be a problem, like adding an amount of crystals to a market, or playing a 50/50 game for example. As the one function is used all over the site, every place will be at risk, rather than just one.

Link to comment
Share on other sites

Were not, thats the point. Ive seen people gain millions on games from putting in negative numbers.

Seems like its 2-0 to me :)

 

In none of my inputs are you able to do that silly nonsense, that is obviously the first thing to block and is as easy as if($var <1 ){ fuck you }

Link to comment
Share on other sites

Yes, it's long winded, and yes, it *is* convenient to drop a lot of

these tests into a function or set of functions however there is NO

security here.

Danny, my users can enter in as many negative digits they want anywhere in any input except the one place where i dont want them to, the bank account, so i would not change the class completely, rather i add that in to my code where i want to block it. I think your magic scoreboard is a little off...

?....?!?? !??

In a very nice and fluent way, you have told us that we should confirm a users input and make sure it is in certain ranges of what you expect it to be. Isn't this already EXTREMELY common knowledge, i mean, of course if you have an input that only needs 100-1000 you would secure it this way. I think what the OP is looking for is not a rehash of, "dont let your visitors enter in negative digits" and "if you want them to not enter in 100 dont let them", i think what he was looking for is help securing user submitted data, although your scripts above do confirm that data actually had been entered, as you stated there is no security.

Until i gave your reply a good look over i assumed what everyone else is, now i see it looks like a show-off reply with no actual answer on how to secure the variables that the user is inputting.

I get a way of validating an integer input as well, if($var < 1){ ##either is not a number, or is smaller than one } success, and in one line.

Edited by runthis
Link to comment
Share on other sites

If you are just going to try and filter the data based on what is in the array, why not like this addition to the original post i made

 

function sanitize( &$data, $whatToKeep )
{
       $data = array_intersect_key( $data, $whatToKeep ); 
       foreach ($data as $key => $value)
       {
               $data[$key] = sanitizeOne( $data[$key] , $whatToKeep[$key] );
       }
}

 

In this example we will assume the get is

 

Array

(

   [id] => blabla77

   [name] => John

   [variable1] => somedata

   [variable2] => somedata

)

 

Now to run a quick filter on this input

 

sanitize($_GET, array( 'id'=>'int', 'name' => 'str') );

 

We end up with

 

Array

(

   [id] => 77

   [name] => John

)

 

So tell me how this is wrong or different from what the OP wants or needs? I am sure i did something horribly wrong that gives Danny more points to his magic scoreboard

Edited by runthis
Link to comment
Share on other sites

I thought this was a place for help not to argue over what is secure and what is not. The only way you can say something is not secure is if you know of a way to get around something. So if you see something you can get around in the code he has posted why not just tell him instead of waiting for something unwanted to happen?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...