I'm reading a book on php security, and on input validation chapter there's a small section that talks about only allowing expected input.
This is the code that they show:
<?php
$expected = array( 'carModel', 'year', 'bodyStyle' );
foreach( $expected AS $key ) {
if ( !empty( $_POST[ $key ] ) ) {
${$key} = $_POST[ $key ];
}
else {
${$key} = NULL;
}
}
?>
I'm kind of confused, there's a small paragraph that explains what the code does. For what I get it assigns a value from the array as a key to $_POST. It also says that the array should be done programatically copied out of the GPC array.
What I don't understand is in what cases should I use this? And what is the GPC array?
GPC = Get Post Cookie, it's referring to variables coming from the user/browser. So instead of using $_GET, $_POST, $_COOKIE you should be cleaning and validating that data into a variable(s) that you can trust and know is clean.
As for the suggestion, what they are doing is limiting what your code has access to. In the above code example, you would probably have a form on the page with elements named carMOdel, year, and bodyStyle. What the code here is doing is restricting your code to ONLY interact with those 3 elements.
This prevents someone from passing extra parameters to your page in an attempt to inject code or some sort of SQL injection attack or any other number of things. In a simple example like this it might not make sense. But there are cases where people are taking form/api requests and running loops over everything in one of GPC arrays and doing stuff with anything in there. I would suggest not doing that to begin with.
This is just 1 of MANY things to protect your server/database. When developing webapps you should take the stance of trusting NOTHING that comes from the user side.
As far as security goes, OWASP is a great source for learning. here is a little cheat sheet that is in the works for php.
The code creates variables from data in the $_POST array. The names of the variables are taken from the keys of the $_POST array. PHP calls this (i.e. naming variables dynamically) variable variables.
This is usually a bad idea, because you do not control, which keys are present in the $_POST array, and thus, which variables are created. The user of your website controls this. A malicious user might name the POST variables in such a way that they overwrite variables that you intended for different purposes.
The book suggests to allow keys in the $_POST array to overwrite variables in a controlled manner. That's what $expected = array('carModel', 'year', 'bodyStyle') is for. This and the following code only creates the variables $carModel, $year and $bodyStyle. If, for example, a user posts current_user_has_admin_rights=1 to you application, a variable $current_user_has_admin_rights with a value of 1 will not be created.
My suggestion is to to stay away from variable variables alltogether and instead access the POST values through the $_POST array only. This makes it clear where the value comes from, an thus makes it easier to spot if such a value is handled in an unsecure manner.
It also says that the array should be done programatically copied out of the GPC array.
This could mean that you shouldn't necessarily write:
$expected = array('carModel', 'year', 'bodyStyle');
Rather write something like:
$expected = getExpectedInput('carForm');
Where the function getExpectInput would query the database for the input that should be in the form 'carForm'. Or perhaps it could be in a file and this function would fetch that content. They basically mean, it's not a good idea to hard-code the variables in the form. Rather write them somewhere so they are easy to change. If you ever made changes to the form and added a variable or changed a variable name, you don't have to change this particular code. This means that this function is usable on different forms. The idea is to write function that that can be re-used. Not those that are dedicated to one thing. OOP.
The getExpectedInput function would probably return an array. You can name this whatever you like or use any method.
Related
Lets say I have an index.php file and some $_GET variables. After a few hundred lines of code I call a method, with the variables as parameters.
Should I validate the variables on top of everything, or should I validate them inside the class/method I call?
2 things in mind:
Avoiding to validate the variables multiple times, everywhere..
Having multiple sources, not only $_GET, and multiple calls to such a method from different files.
Some code:
<?php
function do_something($string) {
// Validate $string here?
}
// ...or here, before using it?
$result = do_something($_GET['some_string']);
This is a question where's no standard solution possible.
You could write yourself a helper class (i recommend this since this is a solution with less maintanance and best flexibility) which is called at the very first beginning of your index.php file, as some kind as a "contract" which is like:
<?
require_once "validator.php";
$validator = new Validator();
$validated = $validator->validateGet($_GET);
// all the remaining site's php code goes here
?>
this class could return anything you want, such like a boolean indicating whether every variable is okay or not, or an array containing the values with removed tags, etc.
Another barrier for cross site scripting and/or SQL injection should be prepared statements: http://php.net/manual/de/pdo.prepared-statements.php
All your SQL queries should also be contained in a external utilities class called ProductDataAccessObject (ProductDAO) or ProductQuerier, etc., which is also for structural/maintanance reasons.
But there's no rule that says "you must validate your variables at the very first beginning or at time of use"
Validate at the very first point when you are receiving $_GET at the entry level so that you are sure for the below code at later stage as well-
// Validate $_GET['some_string'] HERE
$result = do_something($_GET['some_string']);
If you validate here -
function do_something($string) {
// Validate $string here?
}
then there is a possibility that u miss the validation and it will open a loop hole in the code as validation is available only to the method this time.
If you are setting some values for the database, it is a good practice to double check the data and make it safe from code injections.
You can validate on top of the page your every single variable with a one line
$_GET = array_map("mysqli_real_escape_string",$_GET);
Array_map applies one function over every value of an array which in our case is applying mysqli_real_escape_string to the array $_GET
IMPORTANT:
Please do note this is only for sanitization and not validation
You need to validate every variable by your own, for example if what is being sent in an integer, make sure to use intval to validate it
Refer to this question for more information: Sanitization and Validation
I'm not satisfied with your answers yet, I did not ask HOW to validate, I did ask WHERE to do it.
Here is my own suggestion:
As I think the times for procedural coding in PHP are finally over (!!), I dont have any logic inside of my index.php, all logic goes into controller classes.
So you have a data Sender, and data Reciever.
As a Reciever (not only in PHP, it's something very common in realife, too), I have to validate the information sent by the Sender. The Reciever does not trust anybody (this is important in APIs for example). Therefore, validation has to be inside the methods you create, not at the top of index.php files or outside of a class. Imagine someone else using your method, is he going to validate the arguments, or has it been YOUR task? I think it's up to you, so you (the Reciever!) can throw Exceptions.
I also like to keep my data ($_GET, $_POST, ...) as raw as possible outside of the controller. Imagine you have a method which needs validated data at line 100, and a method at line 200 which needs raw data. Now on liee 5 you changed the raw into sanitized. => You have to keep two variables, $data and $data_raw, which is unnecassary overhead.
Think about it
I have a very old client who is now having issues with security because of the MYSQL Injection. This client does not have enough money to change his PHP database functions to PDO or MYSQLI. Nevertheless, he suggested that he wants a function that prevents mysql injuction. He is fully aware that the function is not perfect. But, he does not have any other temporary way right now. the function that I wrote for him is called safe();. Here comes my question. How can I apply the function to all POSTs and REQUESTs in his site. His site has many files, it will take hours to change. is there anything that I can add in the Header of every file that applies my function to all POSTs and REQUESTs variables?
something that maybe looks like this :
$_POST[*] = safe($_POST[*]);
Of course, the above code does not work. but I hope you get the idea.
You can use array_map, but I doubt it'll be perfect solution:
$final = array_map( "mysql_real_escape_string", $_POST );
In the end $_POST and $_GET are just arrays.
You could do a foreach like
foreach ($_POST as $key => $value) {
safe($value);
}
if they have old php servers etc. So if you have a general file that is included over the whole website and the "normal" functions aren't an option, this could be the back-up plan.
You are describing the infamous Magic Quotes, which are still available if the server is older than PHP/5.4.0 (which I presume is the case).
Please note that they affect all POST data, including that which is not going to be injected in a SQL query.
If you prefer your safe() function, you can simply write a simple script that makes the change and call it via auto_prepend_file.
Possible duplicate of https://stackoverflow.com/questions/15664021/php-escaping-vars-posted-through-var-and-got-by-postvari-with-a-meth
As I was told, there's no universal method, but you can give it a try through foreaching the $_POST array
I am thinking of making a loop to gather all my $_POST variables and assign them to dynamically named variables.Something like this (not tested)
for($i; $i <= $_POST[].length; $i++){
${$_POST[i]} = $_POST[i]
}
But I am wondering about the security of something like this. This would then create a variable in the system for every bit of post data sent to the page. Can that variable be damaging even if the script I write doesn't reference it? Is this the type of thing I should avoid entirely? I have some pages that send quite a few variables and a script like this would prevent a whole lot of writing, but is it safe enough?
Yes there are possible security risks.
Say you have a variable $is_admin defined earlier in the code that gives someone admin abilities. If someone POSTS to that page with
$_POST['is_admin'] = true;
Then $is_admin is now true. Not good.
What's wrong with using $_POST?
Yes there can be security concerns/problems, for example one could overwrite any local variables which are already set, like database, config values ect.
So something like this should be avoided:
$yourImportantVar = 'Something relies on this';
//User POSTS yourImportantVar=overwritten
foreach ($_POST as $key => $value) {
$$key = $value;
}
echo $yourImportantVar; //overwritten
But if you want to implement a loop to save a chunk of code, you could create an allowed array which you loop over and extract out the value from the $_POST.
foreach (array(
'name',
'address',
'somethingelse',
'ect'
) as $key) {
$$key = isset($_POST[$key]) ? $_POST[$key] : null;
}
This is a very bad idea for security and maintainability. Simplified example why...
<?php
if (someRandomSessionCheck()) {
$isAdminUser = true;
}
if ($isAdminUser) {
// give access to everything
}
?>
Someone could post to the page with a variable "isAdminUser=1" and would have access to everything.
Another reason it is a bad idea is you can't clearly see from the script where your variables are created. This reduces maintainability of the script. What if you now want to run the script but instead need to get the data from somewhere else and not a POST?
Only issue I can think of at the moment is when that overwrites the existing variable in the scope. This can be very unsafe depending on what you do with it. Think about the variable being the URL you are doing a HTTP request to. Or worse, some flag variable which accesses some critical part of your code.
I will post an example that speaks about HTTP request:
<?php
$url = "http://safe/url/to/POSTto";
$var = array("url" => "http://www.mysite.com/url"); //assume this is $_POST
foreach($var as $key => $value){
${$key} = $value;
}
//now upon the HttpRequest, your site can receive the (critical) data which was actually meant for the safe site.
?>
EDIT: #Galen has posted about the flag variable I was talking about, so may be I need not post any example to highlight the problem.
PHP had a feature (using the term loosely) called register_globals. It has since been deprecated (PHP 5.3) and removed (PHP 5.4), but it mirrored the functionality for which you are looking. It performed the same thing as the PHP function extract() does, which sets variables in the current scope with names of the keys and values of the matching array values.
This is most definitely a security risk. Consider the example of a poor check for authentication:
if($is_logged_in) {
// Allow execution of destructive actions
}
If this feature was enabled (or you mimicked it), a malicious user would be able to set the variable $is_logged_in and bypass the login screen. Don't worry about saving typing. If you need to copy and paste a code block like this at the beginning of your files:
$something = $_POST['something'];
$another = $_POST['another'];
$stuff = $_POST['stuff'];
//etc.
Not only is it much more secure, but it doesn't leave developers (who aren't expecting register_globals) puzzled when undeclared variables start being used. Also, the fact that PHP has removed it and there are plenty of arguments against its use should be evidence enough.
<?php
/* Suppose that $var_array is an array returned from
wddx_deserialize */
$size = "large";
$var_array = array("color" => "blue",
"size" => "medium",
"shape" => "sphere");
extract($var_array, EXTR_PREFIX_SAME, "wddx");
echo "$color, $size, $shape, $wddx_size\n";
?>
Please check this. Same thing what you are going do by using loop. may help you
You are basically implementing extract($_POST, EXTR_OVERWRITE) which will overwrite any already existing variables. The manual already warns to use extract in a way you do:
Do not use extract() on untrusted data, like user input (i.e. $_GET, $_FILES, etc.). If you do, for example if you want to run old code that relies on register_globals temporarily, make sure you use one of the non-overwriting extract_type values such as EXTR_SKIP and be aware that you should extract in the same order that's defined in variables_order within the php.ini.
This can result in overwriting essential and sensitive variables, including those that cannot really be modified directly like $_SESSION, $_SERVER, and $GLOBALS:
POST /foo.php HTTP/1.1
Content-Type: application/x-www-urlencoded
_SESSION[user]=admin
This would have the same effect as $_SESSION = array('user'=>'admin').
For example, I am using a $_POST variable to insert data into a DB. Just before this query I have a few tests and if they are true I want to adjust that (hidden) $_POST value.
Ex.
if($baby_dragon_eats_children){
$_POST['hidden_value'] = "grapes";
}
Can $_POST['hidden_value'] be assigned a new value and then be passed to another function as $_POST and be able to access the new $_POST['hidden_value']?
Thanks
$_POST['consolidate_answers']
IF you assign a value to $_POST you should document is very clearly as it is not common nor considered "best" practice.
IF you have any extensions of PHP such as Suhosin Patch... it may block such actions..
Handle your own arrays, don't depend on $_POST!
IF need be, make a copy of $_POST and work with that.
You can assign values to $_POST, but if you do so you should document it very clearly with comments both at the point of assignment and the later point of access. Manually manipulating $_POST can break future programmers' (including your own) expectations of what is in the superglobal and where it came from.
There may be other alternatives, like:
$my_post = $_POST;
$my_post['hidden_value'] = 12345;
// In a function:
function func() {
// Emulate a superglobal
echo $GLOBALS['mypost']['hidden_value'];
}
Can $_POST['hidden_value'] be assigned a new value and then be passed to another function as $_POST and be able to access the new $_POST['hidden_value']?
It can in normal PHP.
However, extensions like the Suhosin Patch may block this.
Also, it feels wrong in general. $_POST is intended to contain the raw, incoming POST data - nothing else. It should not be modified IMO.
A better way to go would be to fetch all the data you plan to insert into the database into an array, and do the manipulations in that array instead.
You can, it will work, but don't.
Create a copy of $_POST, perform your tests on that and modify that instead. For example.
$postdata = $_POST;
if ($postdata['somevalue'] != 'someothervalue') $postdata['newvalue'] = 'anothervalue';
// ...
If you manipulate variables auto-created by PHP, it will probably come back to haunt you later on when the variable doesn't hold the data you expect it to.
Find an alternative!
The $_POST variable has a distinct responsibility. Do not abuse its globalism.
I'd say don't abuse globalism either way, even if it means changing the design you have (or have in mind).
But if you choose not to, then consider creating a dedicated global registry just for your needs.
Don't manipulate language built-ins.
I'm trying to automate form creation and submission in codeigniter.
Basically what I want is to find a way to go over all the data in the POST array and format it correctly to an insert or update sql query.
The problem is I don't know how to access to whole POST array in CI, all I know of is the $this->input->post(field_name) way which only gives you a specific field.
Ideally I would want to send the POST array to the $this->db->insert_string() or $this->db->update_string() to do the job for me.
I know I can still use the php native $_POST array, but this is not recommended and not as secure as CI's input class.
Anyone know a way to do this?
Thanks,
Amos
Eventually I found out that the input class cleans the $_POST array automatically (not talking about XSS cleaning) and so the only advantage to use $this->input->post(something) is that it checks if that key exists.
Since I need the whole array I don't need that check and can safely use $this->db->insert_string($_POST).
If I you do want XSS cleaning you can either turn it on globally in the config or use geocine's answer (I would go for a mix of the 2 examples he gave).
Another way to go if you want the whole array with XSS cleaning and without it turned on globally is to go with WanWizard's Input library extension found here: http://codeigniter.com/forums/viewthread/172705/#821150
foreach($_POST as $key => $value) {
$value = $this->input->post($key);
//do something
}
or
$keys = array_keys($_POST);
for($i=0,$max=count($keys);$i<=$max;$i++)
{
$value = $this->input->xss_clean($_POST[$keys[$i]]);
//do something
}