i am currently working on making my site injection proof and was wondering about the validations i am making, my code goes like this:
if(!empty($_POST['city']) && !empty($_POST['street'])){
$city = htmlentities(mysql_real_escape_string($_POST['city']));
$street = htmlentities(mysql_real_escape_string($_POST['street']));
}
my question is isnt the empty check itself is a vulnerability?
i mean do i have to escape string in the !empty validation as well? or it is safe to keep it that way?
thanks.
SQL injection vulnerabilities work like this:
$username = $_GET["username"];
mysql_query("SELECT 1 FROM `users` WHERE `username` = '" . $username . "'");
Now if the value of $_GET["username"] is something like "foo' OR 1=1--"
The query:
SELECT 1 FROM `users` WHERE `username` = 'foo' OR 1=1
--'
will be run which selects all users
If you escape your input you will get the (intended) query:
SELECT 1 FROM `users` WHERE `username` = 'foo\' OR 1=1--'
PHP functions themselves aren't vulnerable.
Maybe this a good analogy: when someone says "Say your name" they want you to say "I'm John" not "your name"
For SQL injection you only need to worry when quering the database, so isset is safe.
There should be no need for htmlentities (use it as protection against XSS).
mysql_real_escape_string will protect against SQL injection if done correctly, but should not be used at all, since the mysql_ prefix / DB-handler is outdated, deprecated and should not be used at all.
The safest way is to use either mysqli_ or PDO, and use prepared statements.
Related
Any way to prevent malicious sql statements without using prepared statements and parameterized queries?
Example after simplify:
<?php
$con = mysqli_connect($_POST['db_server'], $_POST['db_user'],
$_POST['db_password'], $_POST['db_database']) or die(mysql_error());
$result = mysqli_query($con, $_POST['query_message']);
?>
Is it possible to check out the parameter $_POST['query_message'] is safe or not?
You should always build your queries within your code and then sanitise any variables you're going to use within them. NEVER pass the query or the database connection variables in via $_POST unless your user is querying the database via that form, in which case I'd recommend you just install phpMyAdmin.
As for sanitising your variables, if you really don't want to use PDO's prepared statements, you can sanitise incoming integers as follows:
$id = (isset($_POST['id']) ? (int)$_POST['id'] : null);
if ($id) {
$sql = "SELECT *
FROM `table`
WHERE `id` = {$id}";
}
And for strings use this:
$username = (isset($_POST['username']) ? mysqli_real_escape_string($con, $_POST['username']) : null);
if ($username) {
$sql = "SELECT *
FROM `table`
WHERE `username` = {$username}";
}
You can also call real_escape_string() directly on your $con object as follows:
$username = (isset($_POST['username']) ? $con->real_escape_string($con, $_POST['username']) : null);
However, as with #Shankar-Damodaran above, I highly suggest you do use PDO prepared statements to query your database.
Why you don't wanna use Prepared Statements ? That is really weird. I strongly suggest you should go for it.
You could make use of mysqli::real_escape_string for escaping quotes that is commonly used for SQL Injection Attacks.
Something like...
OOP Style
$message = $mysqli->real_escape_string($_POST['query_message']);
Procedural Style
$message = mysqli_real_escape_string($link,$_POST['query_message']);
other way is using:
htmlentities($query);
as an extra you could use preg_match() regular expressions to avoid
the inclusion of certain words (SELECT, DROP, UNION .......)
Example:
try{
$query = sprintf("SELECT * FROM users WHERE id=%d", mysqli_real_escape_string($id));
$query = htmlentities($query);
mysqli_query($query);
}catch(Exception $e){
echo('Sorry, this is an exceptional case');
}
There are real world cases where prepared statements are not an option.
For a simple example, a web page page where you can do a search on any number of any columns in the database table. SAy that table has 20 searchable columns. you would need a huge case statement that has all 20 single column queries, all 19+18+17+16+15+14+13+... 2 column queries, all possible 3 column queries... that's a LOT of code. much less to dynamically construct the where clause. That's what the OP means by prepared statements being less flexible.
Simply put, there is no generic case. If there was, php would have it already.
real_escape_string can be beaten. a common trick is to % code the character you are trying to escape so real_escape_string doesn't see it. then it gets passed to mysql, and decoded there. So additional sanitizing is still required. and when all characters used in injection are valid data, it's a PITA, because you can't trust real_escape_string to do it.
If you are expecting an integer, it's super easy.
$sanitized=(int)$unsanitized;
done.
If you are expecting a small text string, simply truncating the string will do the trick. does't matter that it's not sanitized if there's not enough room to hold your exploit
But there is no one size fits all generic function that can sanitize arbitrary data against sql injection yet. If you write one, expect it to get put into php. :)
I want to prevent the 1=1 using the mysql_real_escape_string but not sure if im doing it right because I can still perform 1=1. This is my code:
$memberId = mysql_real_escape_string($_GET["memberId"]);
$sql = "SELECT firstName, lastName, dateSent, message, messageId FROM member, message WHERE member.memberId = message.sentFromId AND message.inboxId=" . $memberId . " ORDER BY dateSent DESC;";
Thanks
mysql_real_escape_STRING() is for STRINGS, not integers. There's nothing in 1=1 that requires escaping, so m_r_e_s() will pass it back unchanged.
if you're dealing with integers, then use integer tools:
$memberID = intval($_GET['memberId']);
The only correct way to not have SQL injections is using prepared statements.
If you attempt to mitigate using escaping you will fail.
If you as a rule never concatenate your queries and always use prepared statements, you have a chance.
It also has the advantage of making your code more readable.
And has no disadvantages.
I am using following method for MySQL queries:
$sql = "SELECT * FROM mytable WHERE `myTableId`=" . (int)$myId;
Is this a completely safe method or is there a way to inject some sql into the database with this method?
Any better alternative?
It can lead to unintended consequences, e.g.
$myId = 'blahblahblah';
would result in
... WHERE myTableId=0
maybe not such a big deal in this case, but if (say) you're doing a permissions systme and "super-duper-ultra-high-level-user-with-more-power-than-god" has permission level 0, then it's a nice way to bypass security.
If you truly want to avoid SQL injection, your best bet is to use PDO and prepared statements. check out http://www.php.net/pdo and http://www.php.net/manual/en/pdo.prepare.php
Thís should be perfectly save, without any drawbacks, as long as the input can be casted to int.
make it like this
$sql="select `username` from `users` where id='$newid';";
mysql_query($sql);
here $newid is the int value.
The symbol used before and after username, to get this you have to press the key just below esc .
I would probably use sprintf instead - but I dont see that it is much different from what you are doing. Placing the integer in quotes may also help.
$sql = sprintf("SELECT * FROM mytable WHERE `myTableId`='%d'", $myId);
Should probably add that you may want to deal with the case when conversion to integer fails. So dont have a table zero.
No need for the Int if you are just worrying about the mysql injection.
To prevent mysql injection you can use mysql_real_escape_string.
What you have right now will block all mysql injection if your mysql condition is only for int but if the situation is like this:
$username = $_GET["username"];
SELECT * FROM customers WHERE username = '$username'
if the $username value is *\' OR 1* your in trouble or i should say your dead
if the $username value is *\'; DELETE FROM customers WHERE 1 or username = * your very dead + doomed
To prevent this from happening use mysql_real_escape_string
$username = mysql_real_escape_string($_GET["username"]);
I've been coding my website in PHP lately and I was pretty proud of myself for my good practices of sanitizing my input before I used it in a query. It was all going great until my friend said I need to sanitize my input. When I tried to explain to him that it was sanitized, he showed me that he had found everything in 'users' table in my database. I didn't know how, so I thought I would post what I was doing wrong that made my sanitizing not work. Here is the PHP code he was exploiting:
start_mysql(); // Starts the databases stuff, etc.
$id = mysql_real_escape_string($_GET['id']);
$game = mysql_query("SELECT * FROM `games` WHERE `id` = $id LIMIT 0, 1");
All he was doing was changing the id parameter, making him able to use SQL injection on my database. I thought mysql_real_escape_string escaped all characters like that, but apparently I was wrong. I did some tests with a normal string to see what would happen, and this is what it said
URL: /game.php?id=' OR '' = '
echo($_GET['id']); // This echo'd: \' OR \'\' = \'
echo(mysql_real_escape_string($_GET['id'])); // This echo'd: \\\' OR \\\'\\\' = \\\'
So, my simple question is, what am I doing wrong?
You need to put the escaped string in single quotes:
WHERE `id` = '$id'
Since id was an integer parameter and you did not surround it in single-quotes in your SQL, the value of $id is sent directly into your query. If you were expecting an integer id, then you should verify that the value of $_GET['id'] is a valid integer.
$id = intval($_GET['id']);
Matt,
mysql_real_escape_string() will only filter for certain characters, if you truly want to prevent injection attacks check out this other Stack Overflow article that suggests you use Prepared statements:
Prepared Statements
PHP Manual entry on Prepared statements
Edit: Also check out Slaks and Michael's postings about wrapping your variable in single quotes.
Good luck!
H
Cast ID. If it is a string it will cast as 0.
$id = (int)$_GET['id'];
Also, MySQL support quotes around both string and numbers in the query.
$game = mysql_query("SELECT * FROM `games` WHERE `id` = '$id' LIMIT 0, 1");
You need to use the parameter binding api. The problem is in this piece of code:
WHERE `id` = $id
You are directly interpolating user input into your SQL statement. That's the open barn door for SQL injection attacks.
You're not using parameterized queries.
MDB2 allows this, though that library may be falling out of favor.
It's very likely that your configuration has magic_quote_gpc, an ancien attempt in PHP to make scripts secure magically. It proved to have multiple flaws and was since deprecated and was scheduled to be completely removed in 5.4 the last time I heard of it.
If you have access to your php.ini configuration, you should disable it. Otherwise, you can modify your script to take it into account and sanitize your input.
All of this is documented here: http://www.php.net/manual/en/security.magicquotes.disabling.php
Otherwise, there is nothing wrong with mysqli_real_escape_string().
You can't prevent SQL injections using mysql_real_escape_string(). It is used for escaping special characters like single quotes ('), double quotes ("), etc.
To prevent SQL injections you have to use PDO statements and filter functions in PHP for sanitizing the user data.
$column = $_GET['id'];
$result = mysql_query("SELECT $column FROM table");
echo $result;
I'm building a website with mysql and am thus trying to learn about sql injections. I assume that this code is vulnerable, but i cant seem to make a working exploit. How would i pull column 'here' from table 'example2'?
Thanks
Imagine $_GET['id'] was equal to something like this
* FROM anytable_i_want; --
the double hypen means the rest of your string is a comment ... so now the sql you're executing is:
SELECT * FROM anytable_i_want;
The single best way to protect from this kind of nonsense is the prepared statement. If you use, say the PDO interface, you do something like this:
$HANDLE = $PDO->prepare('SELECT ? FROM mytable');
$HANDLE->execute(array($_GET['id']));
now no matter what was submitted as $_GET['id'] it woudlnt have any odd effects.
mysql_real_escape_string will cover you if using my mysql_ family of functions, although there is an exploit in the wild that you may be subject to if you change the charset at runtime.
Take a look at PDO and the use of prepared statements to help with preventing SQL injections:
http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
make $column something like :
" here FROM example2 -- "
if the following text was passed as $_GET['id'], you would have an exploit:
$_GET['id'] = '[other sql commands here]';
use either mysql_real_escape_string() or mysqli_real_escape_string() (if you are using the improved interface)