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
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 am implementing a simple closed area on a website.
The access is granted upon entering the right password. The password is shared so no real accounts are in place.
I am trying to understand if i am missing some variable filtering and if i should sanitize the data. I'm pretty sure i must do it, but i don't know what is the best approach.
In my code i have two places where i use the data from the $_POST variable:
if(isset($_POST)&&$_POST['the_password']!="")
{
$my_password = $_POST['the_password'];
//Should i use something like this?
//$my_password = filter_input(INPUT_POST, 'the_password', FILTER_SANITIZE_STRING);
}
The second place is where i use the variable, in an if statement:
if($a_password == $my_password)
{
//Query using the $a_password variable
}
In this part of code $a_password comes from a hard coded query.
Is the filter_input function the right one? Am i missing something?
The short answer is no; for an if statement, your code is safe.
However, if you edit the code later, you should use prepared statements in you database queries.
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.
I have some links structured as follows...
http://domain.com?problem_id=23&course_id=4
The expected values from the GET "fields" (problem_id and course_id) are to be integers. Can I validate this data by simply saying...
if (is_numeric($_GET['problem_id'])){
//It's safe, so do stuff.
} else {
echo 'It appears you submitted a problem incorrectly. Please contact us for assistance';
exit;
}
Or is this still open to nastiness like sql injection, etc.?
PROPOSED SOLUTION
$int_problem_id = (int) $_GET['problem_id'];
if (ctype_digit($int_problem_id)){
//It's safe, so do stuff.
} else {
echo 'It appears you submitted a problem incorrectly. Please contact us for assistance';
exit;
}
Yes, it is a solution. Also, you can additionally cast to int.
$integer = (int) $_GET['problem_id'] ;
You should secure all the input for your database even though numeric values will do no harm as they do not contain special symbols.
You would have ensured that ?problem_id= is numeric. All of your other fields may still be at risk though, so this isn't the proper way of securing against SQL injection. You should look into PDO and MySQLi, and their bindParam/bind_params functions.
I'm sure someone asked this before but I just can't find a post similar.
how necessary is it to validate an ID field from $_GET variable?
I'm using is_numeric() to make sure I'm getting a number at least but am I just putting in unnecessary code?
ex.
www.test.com/user.php?user_id=5
if (isset($_GET['user_id']) && is_numeric($_GET['user_id'])) {
*PDO query for user information*
}
is the is_numeric() necessary?
is there a possibility of an attack by changing user_id in the address?
The best way to sanitize a numeric id is by using an (int) cast.
$id = (int) $_GET['ID'];
with strings you just never know.
Is the is_int() necessary?
You are probably looking for retrieving data by id. Therefore convert the string to an int is the simplest way to go. On a side note is_int will always return false if applied to a string.
Is there a possibility of an attack by changing user_id in the address?
Well, strings are always dirty. You never know what strange characters an user might input and how that will effect the query. For example, I don't know if it can be applied in this case but, you should take a look at NULL bytes attacks.
If you want to properly validate an integer before performing the query, you should use filter_input(); the outcome is either a valid integer, false if it's not a valid integer or null if the parameter wasn't passed at all.
if (is_int($userId = filter_input(INPUT_GET, 'user_id', FILTER_VALIDATE_INT))) {
*PDO query for user information*
}
If you're using prepared statements this won't really matter so much, but if you wish to return a failure response based on whether the input conforms to what's expected, you can use the above.
If you don't want to use prepared statements, PDO::quote should be the correct function:
Returns a quoted string that is theoretically safe to pass into an SQL statement.
is_int will not work, because GET variables are always passed as strings.
Personally, I like to test for a valid integer with:
if(strval(intval($_GET['user_id'])) === $_GET['user_id'])
However, this can be overkill. After all, if you're using prepared statements then there's no need to handle any escaping, and searching for a row that doesn't exist will just return no results. I'd throw in intval($_GET['user_id']), but only to really make it clear to future coders that the ID is a number.
is_int check type of variable. But $_GET['id'] will be always a string. Better use filter_var.
But you must use prepared statement anyway.
P.S. With prepared statements you can not use validation. DB will tell that nothing was found. But if you want to warn user about bad request you must validate it before querying.