I'm using mysqli extension in php for connection to database. I've such a simple question. Is it better to use mysqli instead of mysql and why is it necessary to use mysqli_real_escape_string ? what is this function doing exactly ? Thanks ...
I'll put a little example not using SQL. Imagine you have this PHP code:
<?php
echo 'Hello, world!';
Now you want to replace world with O'Hara:
<?php
echo 'Hello, O'Hara!'; // Parse error: syntax error, unexpected T_STRING, expecting ',' or ';'
Yeah, of course, that is not valid PHP. You need to escape the single quote since it's interpreted as a literal quote rather than the string delimiter:
<?php
echo 'Hello, O\'Hara!';
You have exactly the same problem when composing SQL queries. If you inject random input into your code, sooner or later it'll break. You need to encode input so it's handled as literal input rather than broken code.
How can you do that? Well, MySQL accepts \' just like PHP (though it's only a coincidence: other database engines use other escape methods). So the dumbest solution is to add back slashes here and here:
SELECT id FROM user WHERE name='O\'Hara';
Of course, it's a lot of work to hard-code all the possible characters that need escaping (and you'll probably forget some of them) so you can use a function that does the job for you: either mysql_real_escape_string() or mysqli_real_escape_string().
The question is: is this good enough? Well, it kind of works, but it leads to annoying code that's difficult to maintain:
$sql = "UPDATE user SET name='" . mysql_real_escape_string($name) . "' WHERE id='" . mysql_real_escape_string($id) . "'";
... and you still need to take care of surrounding the complete value with single quotes... which are not always mandatory (think of numbers)... What a mess. Can't someone invent something better? Good news is: they did! It's called prepared statements:
// Just an example, I invented the syntax
$sql = 'UPDATE user SET name=:name WHERE id=:id';
$params = array(
'name' => "O'Brian",
'id' => 31416,
);
$MyDbConnection->execute($sql, $params);
In real life:
MySQLi has the prepare() method to accomplish this. Find some examples there.
Legacy MySQL extension... has nothing: it does not support prepared statements at all! If you use this extension, you are stuck with the annoying add-quotes-yourself and string concatenation methods.
I hope this explains the whole question.
Mysql is slightly faster than Mysqli, but it would have no effect in 99% of web development. The real advantage is that Mysqli is more focused around classes and methods.
Mysqli_real_escape_string is a precautionary function to escape any illegal/malicious characters in a string that you are going to use in a Mysql query. There is also a standard mysql_real_escape_string function aswell. If in doubt it is better to use it than not use it, but beware too many may cause speed issues with your scripts/queries.
To cut it short, if you're writing procedural PHP use standard Mysql, but if you're writing object orientated code then use Mysqli and maximise it's potential. You must always make your queries safe, mysql_real_escape_string is just one way.
Hope this helps!
Related
So basically I’ve been digging deep into the realm of MySQL and PHP…specifically the security measures I should take when dealing with a database and form inputs. So far I’ve found that the following are very strongly recommended:
Prepared Statements
Using mysqli_real_escape_string()
NOT using Magic Quotes as it confuses databases and ends up giving you stuff like “You\’re name isn\’t….”
All of this is great and I’ve been following it. However, I was wondering if one should also escape characters such as the dollars sign [$], percentage sign [%], and possibly others. Couldn’t the query interpret the dollar sign as a PHP variable perhaps? What about LIKE syntax I’ve heard that uses the % symbol or even the wildcard sign? Prepared statements should technically take care of all of this, but I just wanted to be safe and make sure I had everything escaped properly. In the case that I forget to use prepared statements or just neglect to do them, I was hoping this second line of defense per-say could save me a loooong headache.
Here is what I use for escaping currently:
function escape($connection, $data){
$new_data = trim($data);
$new_data = mysqli_real_escape_string($connection, $new_data);
$new_data = addcslashes($new_data, '%_$');
$new_data = htmlspecialchars($new_data, ENT_NOQUOTES);
return $new_data;
}
So is this proper? Am I doing something horrendously wrong? Notice that I would have to remove back slashes before the $, %, and _ characters when retreiving the database data.
You don't need to escape dollar sign. MySQL doesn't treat that character specially, and PHP only recognizes it in source code, not in string values (unless you call eval on the string, but that's a whole other can of worms).
You would only need to escape % and _ if you used user input as the argument to LIKE and you didn't want the user to be able to use wildcards. This could come up if you're processing a search form. You don't need to use it when storing into the database.
You don't need to use htmlspecialchars when accessing the database. That should only be used when you're displaying data to the user in an HTML page, to prevent XSS injection.
Am I doing something horrendously wrong?
Yes.
First on your research.
Prepared Statements is the only great thing you have found.
While use of mysqli_real_escape_string (assuming you are using prepared statements) would be useless and harmful (producing the outcome you have noted yourself: “You\’re name isn\’t….”).
And Magic Quotes has been removed from the language long time ago already - thus, nothing to concern actually.
So, even most of your initial premises are plainly wrong.
Now to your question.
Couldn’t the query interpret the dollar sign as a PHP variable perhaps?
No.
What about LIKE syntax I’ve heard that uses the % symbol or even the wildcard sign?
Yes, you've heard it right. That's exact purpose of LIKE operator - to perform a wildcard search. Disabling these symbols in LIKE would make not a slightest sense.
Means every time you are going to use LIKE operator, you have to decide which particular symbol to use and which to disallow. NO one-for-all solution can be used. Not to mention that in all other mysql interactions % sign has no special meaning at all.
Prepared statements should technically take care of all of this
Prepared statements has nothing to do neither with $ nor with % signs. Prepared statements deal with SQL injections, but neither symbol could cause it (wouldn't you call "injection" a proper intended use of LIKE operator, would you?).
Finally, to the most horrendous part.
In the case you forget to use prepared statements or just neglect to do them,
nothing can save you.
And least help would be from the function you developed.
To sum it all up.
Get rid of this function.
Use placeholders* to represent every single variable in the query.
Escape % and _ symbols in the input data only if it's going to be used in LIKE operator and you don't want them to be interpreted.
Use htmlspecialchars() for output, not mysql input.
*read on prepared statements if the term is unfamiliar to you.
Depending on what kind of data and what it is used for.
If you find PHP default prepared statements are too long and complex to remember I suggest to have look at some classes available on github to give you an idea of simplified queries.
A Good example #
https://github.com/joshcam/PHP-MySQLi-Database-Class
An example of insert queries with this class
$data = Array (
'login' => 'admin',
'active' => true,
'firstName' => 'John',
'lastName' => 'Doe',
'password' => $db->func('SHA1(?)',Array ("secretpassword+salt")),
// password = SHA1('secretpassword+salt')
'createdAt' => $db->now(),
// createdAt = NOW()
'expires' => $db->now('+1Y')
// expires = NOW() + interval 1 year
// Supported intervals [s]econd, [m]inute, [h]hour, [d]day, [M]onth, [Y]ear
);
$id = $db->insert ('users', $data);
if ($id)
echo 'user was created. Id=' . $id;
else
echo 'insert failed: ' . $db->getLastError();
So basically I’ve been digging deep into the realm of MySQL and PHP…specifically the security measures I should take when dealing with a database and form inputs. So far I’ve found that the following are very strongly recommended:
Prepared Statements
Using mysqli_real_escape_string()
NOT using Magic Quotes as it confuses databases and ends up giving you stuff like “You\’re name isn\’t….”
All of this is great and I’ve been following it. However, I was wondering if one should also escape characters such as the dollars sign [$], percentage sign [%], and possibly others. Couldn’t the query interpret the dollar sign as a PHP variable perhaps? What about LIKE syntax I’ve heard that uses the % symbol or even the wildcard sign? Prepared statements should technically take care of all of this, but I just wanted to be safe and make sure I had everything escaped properly. In the case that I forget to use prepared statements or just neglect to do them, I was hoping this second line of defense per-say could save me a loooong headache.
Here is what I use for escaping currently:
function escape($connection, $data){
$new_data = trim($data);
$new_data = mysqli_real_escape_string($connection, $new_data);
$new_data = addcslashes($new_data, '%_$');
$new_data = htmlspecialchars($new_data, ENT_NOQUOTES);
return $new_data;
}
So is this proper? Am I doing something horrendously wrong? Notice that I would have to remove back slashes before the $, %, and _ characters when retreiving the database data.
You don't need to escape dollar sign. MySQL doesn't treat that character specially, and PHP only recognizes it in source code, not in string values (unless you call eval on the string, but that's a whole other can of worms).
You would only need to escape % and _ if you used user input as the argument to LIKE and you didn't want the user to be able to use wildcards. This could come up if you're processing a search form. You don't need to use it when storing into the database.
You don't need to use htmlspecialchars when accessing the database. That should only be used when you're displaying data to the user in an HTML page, to prevent XSS injection.
Am I doing something horrendously wrong?
Yes.
First on your research.
Prepared Statements is the only great thing you have found.
While use of mysqli_real_escape_string (assuming you are using prepared statements) would be useless and harmful (producing the outcome you have noted yourself: “You\’re name isn\’t….”).
And Magic Quotes has been removed from the language long time ago already - thus, nothing to concern actually.
So, even most of your initial premises are plainly wrong.
Now to your question.
Couldn’t the query interpret the dollar sign as a PHP variable perhaps?
No.
What about LIKE syntax I’ve heard that uses the % symbol or even the wildcard sign?
Yes, you've heard it right. That's exact purpose of LIKE operator - to perform a wildcard search. Disabling these symbols in LIKE would make not a slightest sense.
Means every time you are going to use LIKE operator, you have to decide which particular symbol to use and which to disallow. NO one-for-all solution can be used. Not to mention that in all other mysql interactions % sign has no special meaning at all.
Prepared statements should technically take care of all of this
Prepared statements has nothing to do neither with $ nor with % signs. Prepared statements deal with SQL injections, but neither symbol could cause it (wouldn't you call "injection" a proper intended use of LIKE operator, would you?).
Finally, to the most horrendous part.
In the case you forget to use prepared statements or just neglect to do them,
nothing can save you.
And least help would be from the function you developed.
To sum it all up.
Get rid of this function.
Use placeholders* to represent every single variable in the query.
Escape % and _ symbols in the input data only if it's going to be used in LIKE operator and you don't want them to be interpreted.
Use htmlspecialchars() for output, not mysql input.
*read on prepared statements if the term is unfamiliar to you.
Depending on what kind of data and what it is used for.
If you find PHP default prepared statements are too long and complex to remember I suggest to have look at some classes available on github to give you an idea of simplified queries.
A Good example #
https://github.com/joshcam/PHP-MySQLi-Database-Class
An example of insert queries with this class
$data = Array (
'login' => 'admin',
'active' => true,
'firstName' => 'John',
'lastName' => 'Doe',
'password' => $db->func('SHA1(?)',Array ("secretpassword+salt")),
// password = SHA1('secretpassword+salt')
'createdAt' => $db->now(),
// createdAt = NOW()
'expires' => $db->now('+1Y')
// expires = NOW() + interval 1 year
// Supported intervals [s]econd, [m]inute, [h]hour, [d]day, [M]onth, [Y]ear
);
$id = $db->insert ('users', $data);
if ($id)
echo 'user was created. Id=' . $id;
else
echo 'insert failed: ' . $db->getLastError();
Trying to save serialized string to SQL, but then i am having problems with unserializing it because of quotes.
Example, string is "te'st", after serialize we have
s:5:"te'st";
But to save it to SQL we need to add slashes, and i am doing
serialize(addslashes($string))
after this, in our MySQL db we have
s:6:"te'st";
And this is the problem. s:6 means we have 6 symbols string, but our "te'st" is only 5, so when we trying to unserialize it, we getting error.
How to solve it? Tried htmlspecialchars and mysql_real_escape_string
Update:
How i use mysql_real_escape_string
mysql_query("INSERT INTO `table`(`string`) VALUES ('" . serialize(array('iId' =>$aSqlResult['typeID'], 'sName' => mysql_real_escape_string($sScanResultLine))) . "')");
You should pass the data through the escape function after the serialization, not before - which is what you are doing now.
$serialized = mysql_real_escape_string(serialize($data));
Use a parameterised query with PDO or MySQLi and you can forget about the escaping altogether.
You're making a mistake I've seen many making. A bit of a fundamental misunderstanding of how escaping functions and should be used.
You cannot simply chain escape functions and end up with something that's perfect for any context. Your mistake is simple..
You're doing two things:
Serializing an object ( a string in this case )
Saving that into the database.
So before you save it to the database, you must make sure that your value is properly escaped. DO THIS WITH MYSQLI! The mysql_ functions are dead.
The equivalent is mysqli::real_escape_string.
But most importantly.. (sorry for dragging this on)..
serialize modifies the output, it can return a whole bunch of things.. quotes, 0x00's and this is not allowed in mysql queries.
So real_escape_string must obviously be the last step! First serialize, and the escape the output of that function. You did the exact opposite.
In your case the mysql_real_escape_string() is the way to go. It have to work, unless you did it somehow wrong (note: you need to be connected to DB before calling that function). And in fact you should use mysqli_ or PDO, not a mysql_ extension which is now deprecated. Using htmlspecialchars() is simply using wrong tool for the task.
Code should be like this:
mysql_real_escape_string( serialize( $string ) );
I have a standard text input field. It get it's value from $_POST and I use it to build an SQL query (ODBC, not just MySQL, if that makes a difference (or instance, I can't use mysql_escape_string() ) ) .
The query which I am building has single quotes on the PHP and double quotes on the SQL. E.g.:
$sql = 'SELECT * FROM ' . $table . ' WHERE field="' . $_POST['some_field'] . '"";
If the user includes a double quote in his input e.g 6" wrench the I get an SQL error on the unbalanced string (a single quote, as in O'reilly gives no problem).
What's the correct way to handle this? Again, I am using the ODBC interface, not MySQL.
Is it just a matter of addslashes()? Or magic quotes?
Update: the PHP manual says of magic quotes ...
This feature has been DEPRECIATED as of PHP 5.3.0. Relying on this feature is highly discouraged.
(not that they suggests an alternative; in fact, it also says that magic quotes will be dropped in PHP 6)
Should the answer be to use prepared statements?
Use PDO prepared statements. It supports ODBC
Use odbc_prepare and odbc_execute like PDO
Even easier... why not just use htmlspecialchars?
http://us3.php.net/manual/en/function.htmlspecialchars.php
I mean, it's faster, and I'm assuming that the reason why your giving users a data field that allows them to use quotes is because your going to print that data back out at some point. Which is still doable, and you don't have to change around where you store your data.
I'm quite confused now and would like to know, if you could clear things up for me.
After the lateste Anon/Lulsec attacks, i was questioning my php/mysql security.
So, i thought, how could I protect both, PHP and Mysql.
Question: Could anyone explain me, what's best practice to handle PHP and Mysql when it comes to quotes?
Especially in forms, I would need some kind of htmlspecialchars in order to protect the html, correct?
Can PHP be exploitet at all with a form? Is there any kind of protection needed?
Should I use real_escape_string just before a query? Would it be wrong/bad to use it already within PHP (see sanitize_post function)?
Currently i'm using the following function. The function "sanitizes" all $_POST and $_GET variables. Is this "safe"?
function sanitize_post($array) {
global $db;
if(is_array($array)) {
foreach($array as $key=>$value) {
if(is_array($array[$key])) {
$array[$key] = sanitize_post($array[$key]);
} elseif(is_string($array[$key])) {
$array[$key] = $db->real_escape_string(strtr(stripslashes(trim($array[$key])), array("'" => '', '"' => '')));
}
}
} elseif(is_string($array)) {
$array = $db->real_escape_string(strtr(stripslashes(trim($array)), array("'" => '', '"' => '')));
}
return $array;
}
I'm using PHP 5.3.5 with Mysql 5.1.54.
Thanks.
mysql_real_escape_string deserves your attention.
However direct queries are a quagmire and no longer considered safe practice. You should read up on PDO prepared statements and binding parameters which has a side benefit of quoting, escaping, etc. built-in.
BEST practice is always to use prepared statements. This makes SQL injection impossible. This is done with either PDO or mysqli. Forget about all the mysql_* functions. They are old and obsolete.
Question: Could anyone explain me, what's best practice to handle PHP
and Mysql when it comes to quotes?
That's easy: Use prepared statements, e. g. with PDO::prepare or mysqli_prepare.
There is nothing like "universal sanitization". Let's call it just quoting, because that's what its all about.
When quoting, you always quote text for some particular output, like:
string value for mysql query
like expression for mysql query
html code
json
mysql regular expression
php regular expression
For each case, you need different quoting, because each usage is present within different syntax context. This also implies that the quoting shouldn't be made at the input into PHP, but at the particular output! Which is the reason why features like magic_quotes_gpc are broken (always assure it is switched off!!!).
So, what methods would one use for quoting in these particular cases? (Feel free to correct me, there might be more modern methods, but these are working for me)
mysql_real_escape_string($str)
mysql_real_escape_string(addcslashes($str, "%_"))
htmlspecialchars($str)
json_encode() - only for utf8! I use my function for iso-8859-2
mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}')) - you cannot use preg_quote in this case because backslash would be escaped two times!
preg_quote()
Don't waste the effort using mysql_real_escape_string() or anything like that. Just use prepared statements with PDO and SQL injection is impossible.
I usually use the PHP functions stripslashes and strip_tags on the variables as they come in via $_POST (or $_GET, depending on what you use) and mysql_real_escape_string during the query. (I'm not sure if this is "right" but it's worked for me so far.) You can also use PHP's built in validate filters to check things like email addresses, url's, data types, etc. PDO is supposedly decent at preventing SQL injection but I haven't had any experience with it yet.
The basic workflow should be
$data = $_POST['somefield which will go into the database'];
... do data validation ...
if (everything ok) {
$escaped_data = escape_function($data);
$sql = " ... query here with $escaped_data ... ";
do_query($sql);
}
Basically, data that's been escaped for database insertion should ONLY be used for database insertion. There's no point in pre-processing everything and overwriting all data with db-escaped values, when only 2 or 3 of 50(say) values actually go anywhere near the db.
Ditto for htmlspecialchars. Don't send data through htmlspecialchars unless it's headed for an HTML-type display.
Don't store data in the DB formatted for one particular purpose, because if you ever need the data in a different form for some other purpose, you have to undo the escaping. Always store raw/unformatted data in the db. And note: the escaping done with mysql_real_escape_string() and company does not actually get stored in the db. It's there only to make sure the data gets into the database SAFELY. What's actually stored in the db is the raw unescaped/unquoted data. Once it's in the database, it's "safe".
e.g. consider the escaping functions as handcuffs on a prisoner being transferred. While the prisoner is inside either jail, cuffs are not needed.