BeastTheKidd Posted December 27, 2011 Share Posted December 27, 2011 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 Quote Link to comment Share on other sites More sharing options...
Spudinski Posted December 27, 2011 Share Posted December 27, 2011 (edited) 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 December 27, 2011 by Spudinski Quote Link to comment Share on other sites More sharing options...
BeastTheKidd Posted December 27, 2011 Author Share Posted December 27, 2011 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. ? Quote Link to comment Share on other sites More sharing options...
Spudinski Posted December 27, 2011 Share Posted December 27, 2011 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. Quote Link to comment Share on other sites More sharing options...
BeastTheKidd Posted December 27, 2011 Author Share Posted December 27, 2011 Okay. Thanks for your help Spudinski. Much Appreciated Quote Link to comment Share on other sites More sharing options...
Spudinski Posted December 28, 2011 Share Posted December 28, 2011 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. Quote Link to comment Share on other sites More sharing options...
Spudinski Posted December 28, 2011 Share Posted December 28, 2011 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. Quote Link to comment Share on other sites More sharing options...
Spudinski Posted December 28, 2011 Share Posted December 28, 2011 Neither can I see how a GB sized file is relevant. Quote Link to comment Share on other sites More sharing options...
BeastTheKidd Posted December 29, 2011 Author Share Posted December 29, 2011 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 Quote Link to comment Share on other sites More sharing options...
runthis Posted December 29, 2011 Share Posted December 29, 2011 (edited) 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 December 29, 2011 by runthis Quote Link to comment Share on other sites More sharing options...
BeastTheKidd Posted December 29, 2011 Author Share Posted December 29, 2011 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; } } ?> Quote Link to comment Share on other sites More sharing options...
runthis Posted December 29, 2011 Share Posted December 29, 2011 (edited) 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 December 29, 2011 by runthis Quote Link to comment Share on other sites More sharing options...
runthis Posted December 29, 2011 Share Posted December 29, 2011 (edited) ?? Literally makes it easier ... I fail to see why it does not. Uses classic php methods to clean a variable in one line .... Maybe i missed the memo or the easier method than $var=santizeOne($var) ? Edited December 29, 2011 by runthis Quote Link to comment Share on other sites More sharing options...
Danny696 Posted December 29, 2011 Share Posted December 29, 2011 Im not questioning your knowledge here runthis, but from previous posts Octerain seems to know their stuff. And I actually agree with them here, we've seen many functions to try and secure their game easily, but none work, seemingly this one as well. Quote Link to comment Share on other sites More sharing options...
runthis Posted December 29, 2011 Share Posted December 29, 2011 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. Quote Link to comment Share on other sites More sharing options...
Danny696 Posted December 29, 2011 Share Posted December 29, 2011 What if I put in a negative number? It fails right there. Danny 1 - 0 Runthis Quote Link to comment Share on other sites More sharing options...
runthis Posted December 29, 2011 Share Posted December 29, 2011 (edited) it returns negative ..... Danny 0 - 1 Runthis edit: can you explain the situation in which you are asking the user to enter in a negative number? Edited December 29, 2011 by runthis Quote Link to comment Share on other sites More sharing options...
Danny696 Posted December 29, 2011 Share Posted December 29, 2011 Were not, thats the point. Ive seen people gain millions on games from putting in negative numbers. Seems like its 2-0 to me :) Quote Link to comment Share on other sites More sharing options...
bineye Posted December 29, 2011 Share Posted December 29, 2011 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. Quote Link to comment Share on other sites More sharing options...
runthis Posted December 29, 2011 Share Posted December 29, 2011 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 } Quote Link to comment Share on other sites More sharing options...
Danny696 Posted December 29, 2011 Share Posted December 29, 2011 Thats not part of the function though, so that wouldnt secure it itself would it now. No, is that 3-0 to me. I think so. Quote Link to comment Share on other sites More sharing options...
runthis Posted December 29, 2011 Share Posted December 29, 2011 (edited) 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 December 29, 2011 by runthis Quote Link to comment Share on other sites More sharing options...
runthis Posted December 29, 2011 Share Posted December 29, 2011 (edited) 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 December 29, 2011 by runthis Quote Link to comment Share on other sites More sharing options...
runthis Posted December 29, 2011 Share Posted December 29, 2011 Apparently not. I guess everyone has been telling their users "Hey hey hey, please dont enter a number bigger than 50 on that box." before you came along and showed us the way of validation! just kidding :) Quote Link to comment Share on other sites More sharing options...
bluegman991 Posted December 29, 2011 Share Posted December 29, 2011 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? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.