PHP Injection from HTTP GET data used as PHP array key value - php

i would like to know if there is a possible injection of code (or any other security risk like reading memory blocks that you weren't supposed to etc...) in the following scenario, where unsanitized data from HTTP GET is used in code of PHP as KEY of array.
This supposed to transform letters to their order in alphabet. a to 1, b to 2, c to 3 .... HTTP GET "letter" variable supposed to have values letters, but as you can understand anything can be send to server:
HTML:
http://www.example.com/index.php?letter=[anything in here, as dirty it can gets]
PHP:
$dirty_data = $_GET['letter'];
echo "Your letter's order in alphabet is:".Letter2Number($dirty_data);
function Letter2Number($my_array_key)
{
$alphabet = array("a" => "1", "b" => "2", "c" => "3");
// And now we will eventually use HTTP GET unsanitized data
// as a KEY for a PHP array... Yikes!
return $alphabet[$my_array_key];
}
Questions:
Do you see any security risks?
How can i sanitize HTTP data to be able use them in code as KEY of an array?
How bad is this practice?

I can't see any problems with this practice. Anything you... errr... get from $_GET is a string. It will not pose any security threat whatsoever unless you call eval() on it. Any string can be used as a PHP array key, and it will have no adverse effects whatsoever (although if you use a really long string, obviously this will impact memory usage).
It's not like SQL, where you are building code to be executed later - your PHP code has already been built and is executing, and the only way you can modify the way in which it executes at runtime is by calling eval() or include()/require().
EDIT
Thinking about it there are a couple of other ways, apart from eval() and include(), that this input could affect the operation of the script, and that is to use the supplied string to dynamically call a function/method, instantiate an object, or in variable variables/properties. So for example:
$userdata = $_GET['userdata'];
$userdata();
// ...or...
$obj->$userdata();
// ...or...
$obj = new $userdata();
// ...or...
$someval = ${'a_var_called_'.$userdata};
// ...or...
$someval = $obj->$userdata;
...would be a very bad idea, if you were to do it with sanitizing $userdata first.
However, for what you are doing, you do not need to worry about it.

Any external received from GET, POST, FILE, etc. should be treated as filthy and sanitized appropriately. How and when you sanitize depends on when the data is going to be used. If you are going to store it to the DB, it needs to be escaped (to avoid SQL Injection. See PDO for example). Escaping is also necessary when running an OS command based on user data such as eval or attempting to read a file (like reading ../../../etc/passwd). If it's going to be displayed back to the user, it needs to be encoded (to avoid html injection. See htmlspecialchars for example).
You don't have to sanitize data for the way you are using it above. In fact, you should only escape for storage and encode for display, but otherwise leave data raw. Of course, you may want to perform your own validation on the data. For example, you may want dirty_data to be in the list of [a, b, c] and if not echo it back to the user. Then you would have to encode it.
Any well-known OS is not going to have a problem even if the user managed to attempt to read an invalid memory address.

Presumably this array's contents are meant to be publicly accessible in this way, so no.
Run it through array_key_exists()
Probably at least a little bad. Maybe there's something that could be done with a malformed multibyte string or something that could trigger some kind of overflow on a poorly-configured server... but that's pure (ignorant) speculation on my part.

Related

Is it possible to hack a website which use unfiltered GET parameter this way

Is there a way to execute some code on my website, with the following code:
$a = $_GET['a'];
$b = 'abc' . $a;
$c = $a;
And, let's say, there will be no more usage of $a, $b and $c variables in the code - just an assignment and, for example, concatenation. Is it possible to execute some malicious code in this place? (actually I think the answer is no, because then no sanitation would ever be possible at all).
And how about this one (I'm pretty sure, it is vulnerable, if we put some characters into $a, that will be unescaped to commas during some internal http and php proccessing):
$a = $_GET['a'];
$b = "abc $a";
Sorry, I know, this is the basics and silly question, and I should just use some good sanitizer library and don't worry. But I want to be sure, and start with very basics, and I can't say, that the site is 100% secure while it's not getting hacked, I just can say that it is unsecure when one day it occasionally get hacked.
ADDED: Any example of hacking any of this two scripts would be greatly appreciated, I want to hack my own website, which contains code like posted above, to clearly understand, that "in this place, if you program this way, your site will be vulnerable, so you should program it this (another) way.
And, let's say, there will be no more usage of $a, $b and $c variables in the code - just an assignment and, for example, concatenation. Is it possible to execute some malicious code in this place?
No. You have to put the data somewhere where it will be treated as code rather than plain data for there to be a vulnerability. (At least in this context since you don't have to worry about buffer overflows).
And how about this one (I'm pretty sure, it is vulnerable, if we put some characters into $a, that will be unescaped to commas during some internal http and php proccessing):
Again, no. The URL decoding routines themselves don't have any known vulnerabilities, and you aren't putting the data anywhere that a comma will have any significant meaning. Interpolating a string variable into another string is entirely safe. (You might later do something with the resulting string which is unsafe, but that's out of the scope of your question.).
Yes or no, dependant of what is done with this data later.
Yes, if this data is stored, displayed or sent to another systems, because of possible abusing these services (store to SQL could be susceptible to SQLi, display to XSS, etc.). Example:
print($a); // Someone see this in browser or console?
$sqlConnection->insert($a); // Is insert() sanitizing input or not?
No, when You do not use above data processing, and just using it internally like Your examples.
Again, if You output this string even to console or log, it could abuse them and do something undesirable. Better strip unneeded characters from input variables (or take another sanitizing route) and be safe, than sorry after.

In php, using GET command for same parameter multiple times and php tags

First of all, I heard some web-servers allow you to reach parameter with $a instead of $_GET[a], this is not the case here.
Anyway, I have to reach a multiple times, so instead of doing $a = $_GET[a], I instead use $_GET[a] everytime. In single php tag as in <?php ?>, is that an issue, should I absolutely use variables? does it matter?
Another thing is my php file is really scrambled in my html, I wonder if does it matter with multiple gets?(should not, im just worried)
Thanks.
What you refer of using just $a instead of $_GET['a'] (or $_POST['a'] too) is an old feature known as register_globals. This feature was dangerous and leading to messy code, so it was considered deprecated in PHP 5.3 and finally removed in PHP 5.4.
Then, using $_GET['a'] everywhere in your scripts may lead to problems, because you should never trust user input (all things coming from $_GET, $_POST, $_REQUEST, $_COOKIE and some from $_FILES or $_SERVER). It is recommended to do something like $a = sanitize($_GET['a']); (the sanitize function does not exist, depending on what type of value are you expecting, you should check that what you get is an integer, or a valid date, or whatever, depending on your needs). From now on you should stop referencing $_GET['a'] and use instead the new sanitized variable you have just created $a. Because if you were using always $_GET['a'], chances are that you forget to sanitize it someplace.
Also, before sending this sanitized variable into a SQL query, you should escape it or use it inside a prepared statement to avoid SQL injections. Before outputting it to an html for the user to see, use htmlspecialchars to avoid XSS attacks.
And finally, about having multiple php blocks mixed with html blocks, this is only bad for maintenance reasons, because in the long run it will be a complete mess. Try to separate the html you send the user from the php code. Try to read something about the MVC pattern (Model-View-Controller) (this link is probably too complicated or maybe you don't see the utility right now for you that are just beginning with php (at least I didn't see how it was way better than mixing html with php, for all the complexity needed), but try to grasp the idea behind it) .
First of all, I heard some web-servers allow you to reach parameter with $a instead of $_GET[a], this is not the case here.
This is a PHP config setting called register_globals. It is insecure and should NOT be used. See this question for more information.
You can access an element in the $_GET array as many times as you like, it will not cause problems. However if you are printing an element of the $_GET array (or any other user submitted data) to the page, you should run it through htmlspecialchars() or the like before printing it out to prevent XSS vulnerabilities.
using a variable is a preference for you to decide it does not matter. but variable is the way forward if you use the same one multiple times.
<?php echo htmlspecialchars($_GET['a']);?>
using a variable means that it reusable again especially if you have added extra code, which mean just editing one variable for all instances.
<?php $a = htmlspecialchars($_GET['a']);
echo $a;
echo $a;
echo $a;
echo $a;
?>

Sanitizing global arrays in PHP

I'm trying to find the best way to sanitize requests in PHP.
From what I've read I learned that GET variables should be sanitized only when they're being displayed, not at the beginning of the "request flow". Post variables (which don't come from the database) either.
I can see several problems here:
Of course I can create functions sanitizing these variables, and by calling something like Class::post('name'), or Class::get('name') everything will be safe. But what if a person who will use my code in the future will forget about it and use casual $_POST['name'] instead of my function? Can I provide, or should I provide a bit of security here?
There is never a one-size-fits-all sanitization. "Sanitization" means you manipulate a value to conform to certain properties. For example, you cast something that's supposed to be a number to a number. Or you strip <script> tags out of supposed HTML. What and how exactly to sanitize depends on what the value is supposed to be and whether you need to sanitize at all. Sanitizing HTML for whitelisted tags is really complex, for instance.
Therefore, there's no magic Class::sanitize which fits everything at once. Anybody using your code needs to think about what they're trying to do anyway. If they just blindly use $_POST values as is, they have already failed and need to turn in their programmer card.
What you always need to do is to escape based on the context. But since that depends on the context, you only do it where necessary. You don't blindly escape all all $_POST values, because you have no idea what you're escaping for. See The Great Escapism (Or: What You Need To Know To Work With Text Within Text) for more background information on the whole topic.
The variables are basically "sanitized" when PHP reads them. Meaning if I were to submit
"; exec("some evil command"); $blah="
Then it won't be a problem as far as PHP is concerned - you will get that literal string.
However, when passing it on from PHP to something else, it's important to make sure that "something else" won't misinterpret the string. So, if it's going into a MySQL database then you need to escape it according to MySQL rules (or use prepared statements, which will do this for you). If it's going into HTML, you need to encode < as < as a minimum. If it's going into JavaScript, then you need to JSON-encode it, and so on.
You can do something like this... Not foolproof, but it works..
foreach($_POST as $key => $val)
{
//do sanitization
$val = Class::sanitize($val);
$_POST[$key] = $val;
}
Edit: You'd want to put this as close to the header as you can get. I usually put mine in the controller so it's executed from the __construct() automagically.
Replace the $_POST array with a sanitizer object which is beheaving like an array.

$_GET['user'] security vulnerability in PHP

I'm posting it for a clarification in a specific situation, though user input sanitization/validations is a cliche subject.
A section of the code contain
$haystack=$_GET['user'];
$input is never used for 'echo' or 'print' or in any SQL query or in any such thing. The only further use of the user input ( $haystack ) is to check if the string contains a predefined $needle.
if (preg_match($needle,$haystack)) {
$result="A";
} else {
$result="B";
}
My worry is the execution of a malicious code, rather than the presence of it in the user input.
So the question is, if the user input is used only in the context (no usage in echo,print,SQL etc) mentioned above, is there still a possibility of a malicious code in the user input get executed.
I wanted to add the security measures that is just required for the context than overdoing it.
If used only in the context, there's no way to execute malicious code from the user input.
You should be careful with eval, preg_replace (with modifier e, thanks Pelshoff), database queries and echo (& print, sprintf…).
Its not possible to just execute arbitrary code by being able to alter a string. Only when you output the string directly, or use it in SQL should you be really worried.
preg_match won't end up executing your input. It's too simple and straightforward to have a hidden exploitable bug. If you toss $haystack after running preg_match on it, then it can't possibly hurt you.
While the $haystack may not be reflected, it can obviously affect program flow. The (extremely short) code you posted certainly doesn't look directly vulnerable, but not sanitizing your input may enable code execution in conjunction with other vulnerabilities.

The ultimate clean/secure function

I have a lot of user inputs from $_GET and $_POST... At the moment I always write mysql_real_escape_string($_GET['var'])..
I would like to know whether you could make a function that secures, escapes and cleans the $_GET/$_POST arrays right away, so you won't have to deal with it each time you are working with user inputs and such.
I was thinking of an function, e.g cleanMe($input), and inside it, it should do mysql_real_escape_string, htmlspecialchars, strip_tags, stripslashes (I think that would be all to make it clean & secure) and then return the $input.
So is this possible? Making a function that works for all $_GET and $_POST, so you would do only this:
$_GET = cleanMe($_GET);
$_POST = cleanMe($_POST);
So in your code later, when you work with e.g $_GET['blabla'] or $_POST['haha'] , they are secured, stripped and so on?
Tried myself a little:
function cleanMe($input) {
$input = mysql_real_escape_string($input);
$input = htmlspecialchars($input, ENT_IGNORE, 'utf-8');
$input = strip_tags($input);
$input = stripslashes($input);
return $input;
}
The idea of a generic sanitation function is a broken concept.
There is one right sanitation method for every purpose. Running them all indiscriminately on a string will often break it - escaping a piece of HTML code for a SQL query will break it for use in a web page, and vice versa. Sanitation should be applied right before using the data:
before running a database query. The right sanitation method depends on the library you use; they are listed in How can I prevent SQL injection in PHP?
htmlspecialchars() for safe HTML output
preg_quote() for use in a regular expression
escapeshellarg() / escapeshellcmd() for use in an external command
etc. etc.
Using a "one size fits all" sanitation function is like using five kinds of highly toxic insecticide on a plant that can by definition only contain one kind of bug - only to find out that your plants are infested by a sixth kind, on which none of the insecticides work.
Always use that one right method, ideally straight before passing the data to the function. Never mix methods unless you need to.
There is no point in simply passing the input through all these functions. All these functions have different meanings. Data doesn't get "cleaner" by calling more escape-functions.
If you want to store user input in MySQL you need to use only mysql_real_escape_string. It is then fully escaped to store safely in the database.
EDIT
Also note the problems that arise with using the other functions. If the client sends for instance a username to the server, and the username contains an ampersand (&), you don;t want to have called htmlentities before storing it in the database because then the username in the database will contain &.
You're looking for filter_input_array().
However, I suggest only using that for business-style validation/sanitisation and not SQL input filtering.
For protection against SQL injection, use parametrised queries with mysqli or PDO.
The problem is, something clean or secure for one use, won't be for another : cleaning for part of a path, for part of a mysql query, for html output (as html, or in javascript or in an input's value), for xml may require different things which contradicts.
But, some global things can be done.
Try to use filter_input to get your user's input. And use prepared statements for your SQL queries.
Although, instead of a do-it-all function, you can create some class which manages your inputs. Something like that :
class inputManager{
static function toHTML($field){
$data = filter_input(INPUT_GET, $field, FILTER_SANITIZE_SPECIAL_CHARS);
return $data;
}
static function toSQL($field, $dbType = 'mysql'){
$data = filter_input(INPUT_GET, $field);
if($dbType == 'mysql'){
return mysql_real_escape_string($data);
}
}
}
With this kind of things, if you see any $_POST, $GET, $_REQUEST or $_COOKIE in your code, you know you have to change it. And if one day you have to change how you filter your inputs, just change the class you've made.
May I suggest to install "mod_security" if you're using apache and have full access to server?!
It did solve most of my problems. However don't rely in just one or two solutions, always write secure code ;)
UPDATE
Found this PHP IDS (http://php-ids.org/); seems nice :)

Categories