I set a php cookie
setcookie('pr','gulfstream',time()...etc...)
My validation page has arrays and statements as below.
$planes = array('gulfstream','Piper','Citation');
$abc = isset($_COOKIE['pr']) && in_array($_COOKIE['pr'],$planes) ? $_COOKIE['pr']:0;
My visitor pages use:
echo $abc;
Question: is the above safe to output to the page or should I further validate the statement with:
$abc = isset($_COOKIE['pr']) && in_array($_COOKIE['pr'],$planes) ? htmlspecialchars($_COOKIE['pr']):0;
I don't think there's a way to exploit this code in this example.
Anyway I think you have to be aware that it's is to make it exploitable by possibility of type juggling (usually cast to integer 0).
That's why I suggest you to use strict mode of in_array like
in_array($_COOKIE['pr'],$planes, true); //third parameter enforces type checking
Even if you've validated the cookie, it's still meant to contain text, and not HTML code. You should always use htmlspecialchars before outputting text in an HTML document.
Related
Before i make my query, i check if the variable that is to be used in that query is an integer using this code: filter_var($_POST["user_id"], FILTER_VALIDATE_INT) !== false.
My question is, should i use PDO or do any escaping if the above function returns true only if my value is an integer (meaning that the value i am to use to build my query is safe) ? Is there any need to escape the value using prepared statements if my value has already passed the above test ?
I have not done any testing with the above nor am i really experienced in server-side technologies, so it is up to you PHP/security experts to guide me.
It's still a good idea to use prepared statements. Bind functions at this point are tried and true.
What if you or someone else screws up the filter?
Are you going to remember to use the right filter at every point in your code? This is a very easy thing to mismanage, and sometimes you may not be able to plan for every eventuality. Integers are relatively easy, but strings are far more complex.
In regards to your professional reputation, will other people see this code? If you had open source code (like github or something), and I was a hiring manager looking into your history, I would not hire you for breaking such a standard security practice like this.
Admittedly, point 3 is a little off topic, but I feel that it's worth mentioning.
This answer is an explanation of the shorthand type casting, from comments, as it's easier to read it as an answer than as a set of comments.
Your code:
filter_var($_POST["user_id"], FILTER_VALIDATE_INT) !== false.
This is a long winded way of ensuring that POSTed data is integer. It has issues, because POST data is always cast as a string.
$_POST["user_id"] = (int)$_POST["user_id"];
Is much easier to read and shorter to type, and this forces the data to be the integer type. This will competely solve your security risk if putting non-integer data into an integer placement in your SQL.
This utalises PHP Type Juggling which it is well worth reading up on.
While the above code will solve your security aspect, it will raise other overlap issues because any string can be casted to an integer, but the cast will return 0 if the string doesn't start with an integer value.
Example:
$string = "hello";
print (int)$string; // outputs 0;
$string = "27hello";
print (int)$string; // outputs 27;
$string = true;
print (int)$string; // outputs 1;
$string = "";
print (int)$string; // outputs 0;
So, overall I would suggest the following line to ensure your given POST value is a correct integer:
if (strcmp((int)$_POST['value'], $_POST['value']) == 0){
/// it's ok!
}
Please see this answer for further details as well as this PHP manual page.
maybe you need to see php bugs page this page before use FILTER_VALIDATE_INT
I was wondering what is the correct procedure when it comes to security and practicality. Should you use htmlspecialchars() on a variable before you check if it's set and empty?
Examples:
Use htmlspecialchars() on use or storage of post data:
$field = $_POST['field'];
if(isset($field)){
//store or use: htmlspecialchars($field);
}
Or should you use htmlspecialchars() on retrieval of the post data:
$field = htmlspecialchars($_POST['field']);
if(isset($field)){
//store or use: $field
}
This is probably a silly question, but I wanted to know which is correct.
Well, think about it this way. Why do we use isset in the first place? The answer is to protect our code from trying to do things with something that doesn't exist.
For example, using php -a in your console, you can see:
php > $temp
php > echo htmlspecialchars($temp);
Parse error: parse error in php shell code on line 2
php >
Clearly you don't want your code throwing parse errors. So, you need to check that the value exists first (using isset), then do things with that value.
You should use both isset and empty if you want to make your condition fully secure, Because isset checks that variable is defined or not and empty checks for the value of variable is empty or not.
So you should use your if condition like this,
$field = $_POST['field'];
if(isset($field) && !empty($field)){
//store or use: htmlspecialchars($field);
}
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;
?>
might be a silly question nonetheless:
I'm playing around with the following code:
$a='a';
if ($_GET['a'] == $a)
echo 'true';
else
echo 'false';
Now, is there any way to send data to break the verification? Obviously the way it could've been done in an SQL injection won't go.
Just wondering how secure this way of validation is.
Thanks in advance.
EDIT:
My question was, is there anything that can be passed thorugh $_GET that could 'break' the comparison and always output 'true'.
If you are looking to validate that $_GET['a'] really in face equals to "a" and nothing else, than yes, that's the code.
However, if you're expecting "a" and only "a" it probably shouldn't be a user input.
Validation (or sanitation), means to take whatever string they might throw at you, and make sure it's valid for whatever purpose you want it to. If it's sent to the database, pass it through mysql_escape_string() or use prepared statements. If it's to be displayed as HTML make sure there aren't any harmful tags by using html_entities() or strip_tags().
Your verification isn't very good for anything else other than saying the user has inputted "a". But yes, nothing other than "a" would be able to get through.
Well, if you knew exactly what was coming in, you could compare without type coercion and check for an empty parameter:
$a = 'a';
if( !empty( $_GET['a'] ) && $_GET['a'] === $a )
{
//do more validation using your data model
}
else
{
//output error msg
}
You could use Prepared-Statements from the mysqli extension this already prevents every possible injection.
If you don't want to use such mysql and mysqli also have "real_escape_string"-methods which you can use in your Query when putting in Userinput
Example
$sql = "SELECT `name` FROM `example` WHERE `id` = '".mysql_real_escape_string($YOURVAR)."'";
real_escape_string method from standart mysql extension
mysqli real_escape_string
Is this enough?
$listing = mysql_real_escape_string(htmlspecialchars($_POST['listing']));
Depends - if you are expecting text, it's just fine, although you shouldn't put the htmlspecialchars in input. Do it in output.
You might want to read this: What's the best method for sanitizing user input with PHP?
you can use php function : filter_var()
a good tutorial in the link :
http://www.phpro.org/tutorials/Filtering-Data-with-PHP.html
example to sanitize integer :
To sanitize an Integer is simple with the FILTER_SANITIZE_INT filter. This filter strips out all characters except for digits and . + -
It is simple to use and we no longer need to boggle our minds with regular expressions.
<?php
/*** an integer ***/
$int = "abc40def+;2";
/*** sanitize the integer ***/
echo filter_var($int, FILTER_SANITIZE_NUMBER_INT);
?>
The above code produces an output of 40+2 as the none INT values, as specified by the filter, have been removed
See:
Best way to stop SQL Injection in PHP
What are the best practices for avoid xss attacks in a PHP site
And sanitise data immediately before it is used in the context it needs to be made safe for. (e.g. don't run htmlspecialchars until you are about to output HTML, you might need the unedited data before then (such as if you ever decide to send content from the database by email)).
Yes. However, you shouldn't use htmlspecialchars on input. Only on output, when you print it.
This is because, it's not certain that the output will always be through html. It could be through a terminal, so it could confuse users if weird codes suddenly show up.
It depends on what you want to achieve. Your version prevents (probably) all SQL injections and strips out HTML (more exactly: Prevents it from being interpreted when sent to the browser). You could (and probably should) apply the htmlspecialchars() on output, not input. Maybe some time in the future you want to allow simple things like <b>.
But there's more to sanitizing, e.g. if you expect an Email Address you could verify that it's indeed an email address.
As has been said don't use htmlspecialchars on input only output. Another thing to take into consideration is ensuring the input is as expected. For instance if you're expecting a number use is_numeric() or if you're expecting a string to only be of a certain size or at least a certain size check for this. This way you can then alert users to any errors they have made in their input.
What if your listing variable is an array ?
You should sanitize this variable recursively.
Edit:
Actually, with this technique you can avoid SQL injections but you can't avoid XSS.
In order to sanitize "unreliable" string, i usually combine strip_tags and html_entity_decode.
This way, i avoid all code injection, even if characters are encoded in a Ł way.
$cleaned_string = strip_tags( html_entity_decode( $var, ENT_QUOTES, 'UTF-8' ) );
Then, you have to build a recursive function which call the previous functions and walks through multi-dimensional arrays.
In the end, when you want to use a variable into an SQL statement, you can use the DBMS-specific (or PDO's) escaping function.
$var_used_with_mysql = mysql_real_escape_string( $cleaned_string );
In addition to sanitizing the data you should also validate it. Like checking for numbers after you ask for an age. Or making sure that a email address is valid. Besides for the security benefit you can also notify your users about problems with their input.
I would assume it is almost impossible to make an SQL injection if the input is definitely a number or definitely an email address so there is an added level of safety.