Is mysql_real_escape_string supposed to replace both addslashes() and stripslashes()??
ie.. do I use it to encode form input variables on MySQL inserts as well as use it in place of stripslashes on MySQL select statements?
Sincerely,
Confused PHP noob
If you are using the regular MySQL driver module for PHP, then yes, mysql_real_escape_string() is the way to go. You can ignore addslashes() and stripslashes() entirely, in fact.
Your query creation will look something like this:
$sql = "INSERT INTO tbl (x) VALUES '".mysql_real_escape_string($x)."'";
mysql_real_escape_string() should be used on any user input that is going into your query. Note that you don't want to escape your data any other way before inserting it. You shouldn't use addslashes() or htmlentities(), which are common mistakes when storing HTML fragments in a database. You should not need to unescape your data in any way after you have retrieved it.
As other posters mention, there are other MySQL database driver modules for PHP, including PDO and MySQLi. Both offer a feature known as prepared statements, which is an alternative method of creating queries that handles escaping for you.
I recommend using PDO and prepared statements instead; see the PDOStatement class. Prepared statements can be more efficient (if the engine doesn't have to reparse your SQL). They should also prevent you from accidentally storing escaped data in the db (double-escaping). Using PDO will make it easier to add support for other databases.
Yes, it should do all the backslashing for you (based upon whatever charset the mysql server is)
Yes, it should escape strings in preparation for use in MySQL. However, it is not the be-all, end-all of avoiding SQL injection. It does in fact leave you very vulnerable to it still.
Better to use the PHP PDO instead, parameterized queries are the way to go ;)
I'd recommend using prepared statements. That way you won't have the hassle of manually escaping every query.
$stmt = $db->prepare("SELECT stuff FROM table WHERE something = ?");
$stmt->execute('s', 'something'); // s means string
Another option is to use PDO, which is an even better version of this, and generally database independent.
http://php.net/manual/en/function.mysql-real-escape-string.php
You wouldn't want to use addslashes() and stripslashes(). If I recall correctly, mysql_real_escape_string() is more similiar to addslashes(), but it escapes different characters.
Related
I read this comment on the mysql_real_escape_string php documentation page:
Also don't forget to escape $_COOKIE array before querying the database. In firefox you can edit cookies and insert and inject harmful sql queries.
<?php
foreach ($_COOKIE as $key => $value) {
if(get_magic_quotes_gpc()) $_COOKIE[$key]=stripslashes($value);
$_COOKIE[$key] = mysql_real_escape_string($value);
}
?>
Am I right in thinking I only have to do this if I use these cookie values in a query? So if no sql statement uses values from these cookies there is no need to escape the cookies like above?
I am using mysql_query not prepared statements (all the inhouse company code I am working with uses mysql_query)
You just need to remember this concept once: Whenever you concatenate one string into a special text format, you need to escape it according to that format at the moment of concatenation. It doesn't matter where that value comes from. You do not escape values before or after concatenating them, but right when you do. You do not blanket escape your cookie values just because. You escape a value you want to put into an SQL query right when you put it in there. Cookies are no special case; it's sad enough that the reminder needs to be there.
Your code is always:
$sql = sprintf("SELECT ... WHERE foo = '%s'", mysql_real_escape_string($var));
It's not:
$var = mysql_real_escape_string($var);
// 100 lines of irrelevant code
$sql = "SELECT ... WHERE foo = '$var'";
Read The Great Escapism (Or: What You Need To Know To Work With Text Within Text).
Am I right in thinking I only have to do this if I use these cookie values in a query?
Yes... ish.
You shouldn't overwrite superglobals with data that is only fit for stuffing in a MySQL query. Do escaping at the last minute and to local variables.
There are better ways to defend against SQL injection then variable escaping anyway.
I am using mysql_query not prepared statements (all the inhouse company code I am working with uses mysql_query)
I suggest starting the migration process. It will be less painful then having to do it all in one go when you want to upgrade to a future version of PHP that doesn't have the deprecated library in it.
Yes, you are right in assuming this is only required when using them in database queries.
No, you should definitely not do it globally for ALL cookies.
No, you should never concatenate cookie values in SQL queries anyway, use prepared statements.
mysql_real_escape_string is deprecated with its entire family of mysql_ functions since PHP 5.5. Switch to PDO or MySQLi instead. And use their faciliteit for prepared statements to remove all worries about SQL injection.
You can edit cookies in every browser, not just Firefox.
Am I right in thinking I only have to do this if I use these cookie
values in a query? So if no sql statement uses values from these
cookies there is no need to escape the cookies like above?
yes, of course ;)
I am using mysql_query not prepared statements (all the inhouse
company code I am working with uses mysql_query)
Try to migrate to prepared statements with either PDO or mysqli
If you cannot migrate: Note that you'll have to establish the mysql connection before you call mysql_real_escape_string()! That's because the function uses the current connection encoding to properly escape strings. If you connect afterwards the escaping might be wrong.
This reminder is there to tell you, that you can't trust values you get from cookies, even if you set them yourself, because anyone can alter them. So, yes.
Of course you should not use mysql_ functions and all that, but I think you know that (have to use them in an older application, too).
Is it totally safe to insert array serialized with serialize() into db, or I should do addslashes(serialize($array)) before? Or there can be some mysql specific characters? Can I delete data or whatever with insert?
No it is not safe at all.
And you should never use addslashes but mysql_real_escape_string instead. Or even better, use PDO with prepared statements instead of escaping.
It's totally ***un****safe* to insert the serialized data in the database without database-specific processing.
You should use whatever mechanism is recommended for preventing SQL injections with your chosen database access layer; making the queries safe against injections includes properly escaping the data as well, so you 'll hit two birds with one stone.
See How can I prevent SQL injection in PHP? for specific examples.
I've read in several places that htmlspecialchars is not enough to prevent SQL injection attacks. I'm working with a legacy codebase and it uses this to sanitize user input:
stripslashes(htmlspecialchars(trim($value), ENT_QUOTES, 'UTF-8'))
My gut tells me that this is also unsafe but my coworker insists that it is. I don't have much experience in working with plain PHP so could someone please tell me why this is unsafe so that I can convince my coworker to use something better?
I've read in several places that htmlspecialchars is not enough to prevent SQL injection attacks
It protects against XSS attacks, but SQL is not HTML so it does nothing for SQL injection.
(You should move the htmlspecialchars encoding to "before inserting into HTML" instead of "before inserting into SQL")
My gut tells me that this is also unsafe but my coworker insists that it is.
Your gut is right. The fact it leaves quote characters alone shouts unsafe!.
Take a look at Bobby Tables. It demonstrates the problem and provides a number of solutions. Anything that uses bound parameters is good.
Use prepared statements.
disable magic quote in php.ini and use PDO. bum
htmlspecialchars to escape params in SQL is the ugliest
It may prevent you from XSS, but not from SQLi, because it doesn't quote any SQL-specific (or DBMS-specific) special characters. The most modern solution is to use PDO with Prepared Statement or PDO:quote(). Legacy solutions cover mysql_escape_string() and such. Refer the manual about the db-driver you are using, about the features it provides to prevent you from SQLi.
You should be calling a database specific escaping function on things you insert into queries.
For a MYSQL database, use mysql_real_escape_string.
It depends on the type of SQL query it is injecting. SQL injections in string fields (enclosed with ' and ") can be disabled by encoding or removing this characters. But in general this is not the solution!
You should NEVER EVER concatenate the SQL string together and send it to the database, especially if it contains user supplied data. You should always use the prepare statement to prepare a SQL statement with placeholders and then pass the parameters separately. Yes, this means that you will probably need to have more than one line of code and you will call corresponding SQL functions.
This is the only good solution for this that is implemented in all programming languages.
mysql_real_escape_string would be better than mysql_escape_string as it has been deprecated.
I am trying to create some SQL insert statements and a few variables have names like the following:
"Aamma's Pastries"
I want to escape the quote (') as I am adding the value into the MySQL database. How do I do that with PHP?
You've already accepted an answer, but I'd like to suggest a better approach to you. Using an approach like mysql_real_escape_string requires you to consistently remember to apply it every single time in every single query; it's tedious and error prone.
A more simple approach, which also ensures consistency is to use parameterised statements. This ensures that everything is correctly escaped, and also avoids you having to embed variables in your queries.
In PHP, this can be used with the newer PDO or MySQLi libraries. Of these, I prefer PDO for the flexibility it provides (e.g. I'm currently stuck with MySQL, but I don't intend to keep my app running that way forever, and with PDO the migration will be massively simplified), but there are plenty of questions here on SO that cover the pros and cons of each.
Have a look at mysql_real_escape_string
Please use prepare statements and let mysql handle escaping itself and you doing at code level
There is this function that you can use that escapes all characters that you need, here is a code example in php
<?php
$str = "Is your name O'reilly?";
// Outputs: Is your name O\'reilly?
echo addslashes($str);
?>
Is mysql_real_escape_string sufficient for cleaning user input in most situations?
::EDIT::
I'm thinking mostly in terms of preventing SQL injection but I ultimately want to know if I can trust user data after I apply mysql_real_escape_string or if I should take extra measures to clean the data before I pass it around the application and databases.
I see where cleaning for HTML chars is important but I wouldn't consider it necessary for trusting user input.
T
mysql_real_escape_string is not sufficient in all situations but it is definitely very good friend. The better solution is using Prepared Statements
//example from http://php.net/manual/en/pdo.prepared-statements.php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
Also, not to forget HTMLPurifier that can be used to discard any invalid/suspicious characters.
...........
Edit:
Based on the comments below, I need to post this link (I should have done before sorry for creating confusion)
mysql_real_escape_string() versus Prepared Statements
Quoting:
mysql_real_escape_string() prone to
the same kind of issues affecting
addslashes().
Chris Shiflett (Security Expert)
The answer to your question is No. mysql_real_escape_string() is not suitable for all user input and mysql_real_escape_string() does not stop all sql injection. addslashes() is another popular function to use in php, and it has the same problem.
vulnerable code:
mysql_query("select * from user where id=".mysql_real_escape_string($_GET[id]));
poc exploit:
http://localhost/sql_test.php?id=1 or sleep(500)
The patch is to use quote marks around id:
mysql_query("select * from user where id='".mysql_real_escape_string($_GET[id])."'");
Really the best approach is to use parametrized queries which a number of people ahve pointed out. Pdo works well, adodb is another popular library for php.
If you do use mysql_real_escape_string is should only be used for sql injection, and nothing else. Vulnerabilities are highly dependent on how the data is being used. One should apply security measures on a function by function basis. And yes, XSS is a VERY SERIOUS PROBLEM. Not filtering for html is a serious mistake that a hacker will use to pw3n you. Please read the xss faq.
To the database, yes. You'll want to consider adequately escaping / encoding data for output as well.
You should also consider validating the input against what you expect it to be.
Have you considered using prepared statements? PHP offers numerous ways to interact with your database. Most of which are better than the mysql_* functions.
PDO, MDB2 and the MySQL Improved should get you started.
What situations?
For SQL queries, it's great. (Prepared statements are better - I vote PDO for this - but the function escapes just fine.) For HTML and the like, it is not the tool for the job - try a generic htmlspecialchars or a more precise tool like HTML Purifier.
To address the edit: The only other layer you could add is data valdation, e.g. confirm that if you are putting an integer into the database, and you are expecting a positive integer, you return an error to the user on attempting to put in a negative integer. As far as data integrity is concerned, mysql_real_escape_string is the best you have for escaping (though, again, prepared statements are a cleaner system that avoids escaping entirely).
mysql_real_escape_string() is useful for preventing SQL injection attacks only. It won't help you with preventing cross site scripting attacks. For that, you should use htmlspecialchars() just before outputting data that was originally collected from user input.
There are two ways, one is to use prepared statements (as mentioned in other answers), but that will slow down your app, because you now have to send two requests to the Database, instead of one. If you can live with the reduced performance, then go for it; Prepared Statements makes your code prettier and easier to deal with.
If you chose to use mysql_real_escape_string, then make sure that you escape all the strings that are untrusted. An (mysql_real_escape_string) escaped string is SQL Injection secure. If you don't escape all the strings, then you are not secure. You should really combine mysql_real_escape_string with input validation; checking that a variable you expect to hold a number really is a number and within the expected range. Remember, never trust the user.
There are different types of "cleaning".
mysql_real_escape_string is sufficient for database data, but will still be evaluated by the browser upon display if it is HTML.
To remove HTML from user input, you can use strip_tags.
I would suggest you look into using PDO instead of regular MySQL stuff, as it supports prepared statements right out of the box, and those handle the escaping of invalid data for you.
You can try both, as in
function clean_input($instr) {
// Note that PHP performs addslashes() on GET/POST data.
// Avoid double escaping by checking the setting before doing this.
if(get_magic_quotes_gpc()) {
$str = stripslashes($instr);
}
return mysql_real_escape_string(strip_tags(trim($instr)));
}
The best way to go would be to use Prepared Statements
I thought I'd add that PHP 5.2+ has input filter functions that can sanitize user input in a variety of ways.
Here's the manual entry as well as a blog post [by Matt Butcher] about why they're great.