I use mysql_real_escape_string() to validate all user inputs before I insert them in a sql database. One of the fields is name, and we've had issues with users with names like O'Reilly. Is there any way to use mysql_real_escape_string() to block injections but allow these names in the db?
The problem is most likely that the apostrophes get quoted twice: first by the evil and deprecated in 5.3 magic quotes and then by mysql_real_escape_string().
What you can do is either disable magic quotes or run stripslashes() on your input values before feeding them to mysql_real_escape_string()
Brief explanation of the problem:
the user enters O'Reilly
magic quotes automatically turn it into O\'Reilly
the script feeds the string through mysql_real_escape_string() which escapes both the backslash and the apostrophe (again) yielding O\\\'Reilly
the query is executed, the quoting is processed and the database understands that you want a backslash and an apostrophe since they where both escaped, and records O\'Reilly
As already mentionned : mysql_real_escape_string is not meant for input validation. If you want to validate inputs, use your own functions or the filter functions from php.
If you have too many slashes added automatically by php, disable magic quotes.
To prevent SQL injection, use parameterized queries with either PDO or mysqli.
+1 for using PDO. I've been using PDO in favour of a MySQL class acting as a database abstraction layer for a few months now and it's a breeze.
Traditionally, developers would use the stripslashes() function on data before applying a function like mysql_real_escape_string(). It's still a good idea to remove slashes from input data, but you can then either use the PDO method for escaping data (PDO::quote($data)) or binding the parameter.
Your query block would then look something like this:
$pdo = new PDO(DSN, DB_USER, DB_PASS);
$sql = "INSERT INTO table (field1, field2) VALUES (:value1, :value2)";
$smt = $pdo->prepare($sql);
$smt->bindParam(':value1', $value1, PDO::PARAM_STR);
$smt->bindParam(':value2', $value2, PDO::PARAM_STR);
$smt->execute();
$rows = $smt->rowCount(); // returns number of rows affected
I hope this helps somewhat. Take a look at http://php.net/manual/en/book.pdo.php for more information on PDO in PHP.
Related
I was reading lots of forums and answers on Stack over flow regarding SQL-Injection
and i came to know this is very basic level of SQL-injection
$_POST['name'] = 'xyz;DROP Table users';
mysqli_query ('select * from abc where name='."$_POST['name']")
To prevent this
Use mysqli_escape_stirng on any input that comes from user can save me from SQl-injection
Use PDO and prepare statement can also save me from SQL-injection
Q1. What i want to know here how passing data to Mysqli_escape_string can save me from SQL-Injection
$safe_variable = mysqli_escape_String($connection ,$_POST['name'];
How mysqli_escape_string will only save "XYZ" from POST data and leave the rest of the part (if that is the case)
Q2. How PDO will save me from SQL-Injection
$stmt = $dbh->prepare("select * from ABC where name = :name");
$stmt->bindParam(':name',$name);
$name = $_POST['name'];
$stmt->execute();
Any help in this regard his highly appreciated
The problem with incorporating user input into SQL is that in the resulting SQL you can’t tell which parts were provided by the developer and which by the user. That’s why the developer must ensure that user input gets interpreted as intended.
This is where string escaping functions and parameterization come in:
String escaping functions like mysqli_real_escape_string process the value so that it can be securely used in a string literal without fearing it may be interpreted as anything else than string data.
However, it is important to note that the value is actually placed in a string literal and nowhere else as it’s only intended for that specific purpose, i. e., it ensures that the passed data is interpreted as string data only when placed inside a string literal. Unfortunately, the PHP manual fails to mention the string literal part.
Parameterization as implemented by prepared statements separate the SQL and the data parameters. So there can’t be a confusion of SQL code and provided data. With server-side prepared statements first the statement gets prepared having only parameter placeholders and then the parameter values get passed for execution. And whenever a parameter is encountered, the DBMS uses the corresponding parameter value.
As for your specific example:
What i want to know here how passing data to Mysqli_escape_string can save me from SQL-Injection
$safe_variable = mysqli_escape_String($connection ,$_POST['name'];
How mysqli_escape_string will only save "XYZ" from POST data and leave the rest of the part (if that is the case)
It doesn’t because you didn’t put the value in a string literal. However, the following would work:
mysqli_query("select * from abc where name='$safe_variable'")
How PDO will save me from SQL-Injection
$stmt = $dbh->prepare("select * from ABC where name = :name");
$stmt->bindParam(':name',$name);
$name = $_POST['name'];
$stmt->execute();
As already said, you explicitly state what the SQL looks like by preparing the statement. And then you pass the parameters for execution. As the parameterized SQL and its parameters are separated, they won’t mix and a passed parameter value can’t be mistaken as SQL.
Q1:
mysql(i)_real_escape_string() calls MySQL's library function
mysql(i)_real_escape_string, which prepends backslashes to the following
characters: \x00, \n, \r, \, ', " and \x1a.
(http://php.net/mysqli_real_escape_string)
Note that this depends on the character encoding (not workin in this case is SET NAMES ... (security risk!!!), $mysqli->set_charset('utf8'); should be used!). (You can read about encoding in my post Mastering UTF-8 encoding in PHP and MySQL.)
How does it prevent SQL injection?
- Well it prevents breaking the variables context by escaping ' etc, the thing is, that mysql_query and mysqli_query only execute one query per query, that means, it simply ignores ;DROP Table users.
mysqli_real_escape_string DOES NOT prevent inserting code like DROP DATABASE.
Only PDO and/or mysqli_multi_query are vulnerable in this case.
Q2:
The statement is sent to the server first, then the bound variables will get sent seperated and then the statement gets executed, in this case, the security is provided by the database library, not by the client library. You should prefere this.
That means, you first send $dbh->prepare("select * from ABC where name = :name"); to the server and the database knows your bind param will be inserted into the :name placeholder and it will automatically wrap it properly to not break out of its supposed context. The database will try to look for a name value of xyz;DROP Table users and it won't executed any command, just fill that variable space.
I think this is the case for most SQL escaping functions:
They escape the control chars like ;, ', ", ...
So your string
xyz;DROP Table users
Will be escaped by the functions to
xyz\;DROP Table users
So your string now isn't a valid SQL command anymore.
But be aware of HTML tags in the data stored in a DB.
If I insert for example
<script>alert('foobar');</script>
This will be stored in DB and not treated by the SQL escape functions. If you print out the field somewhere again, the JS will be executed by the visitors browser.
So use in addtion htmlspecialchars() or htmlentities() for sanitize user input. This is also true for prepared statements.
I am using the code shown here, it uses addslashes() on the data fetched from the database before saving to file.
$row[$j] = addslashes($row[$j]);
My question is why and do I need to use this? I thought you would do this when saving to the database not the other way round. When I compare the results from the above script with the export from phpMyAdmin, the fields that contain serialized data are different. I would like to know if it would cause any problems when importing back into the database?
Script:
'a:2:{i:0;s:5:\"Hello\";i:1;s:5:\"World\";}'
phpMyAdmin Export:
'a:2:{i:0;s:5:"Hello";i:1;s:5:"World";}'
UPDATE
All data is escaped when inserting into the database.
Change from mysql to mysqli.
SQL file outputs like:
INSERT INTO test (foo, bar) VALUES (1, '\'single quotes\'\r\n\"double quotes\"\r\n\\back slashes\\\r\n/forward slashes/\r\n');
SOLUTION
Used $mysqli->real_escape_string() and not addslashes()
inserting to db
When inserting data to a MySQL database you should be either using prepared statements or the proper escape function like mysql_real_escape_string. addslashes has nothing to do with databases and should not be used. Escaping is used as a general term but actually covers a large number of operations. Here it seems two uses of escaping are being talked about:
Escaping dangerous values that could be inserted in to a database
Escaping string quotes to avoid broken strings
Most database escaping functions do a lot more than just escape quotes. They escape illegal characters and well as invisible characters like \0 ... this is because depending on the database you are using there are lots of ways of breaking an insert - not just by adding a closing quote.
Because someone seems to have missed my comment about mentioning PDO I will mention it again here. It is far better to use PDO or some other database abstraction system along with prepared statments, this is because you no longer have to worry about escaping your values.
outputting / dumping db values
In the mentioned backup your database script the original coder is using addslashes as a quick shorthand to make sure the outputted strings in the mysql dump are correctly formatted and wont break on re-insert. It has nothing to do with security.
selecting values from a db
Even if you escape your values on insert to the database, you will need to escape the quotes again when writing that data back in to any kind of export file that utilises strings. This is only because you wish to protect your strings so that they are properly formatted.
When inserting escaped data into a database, the 'escape sequences' used will be converted back to their original values. for example:
INSERT INTO table SET field = "my \"escaped\" value"
Once in the database the value will actually be:
my "escaped" value
So when you pull it back out of the database you will receive:
my "escaped" value
So when you need to place this in a formatted string/dump, a dump that will be read back in by a parser, you will need to do some kind of escaping to format it correctly:
$value_from_database = 'my "escaped" value';
echo '"' . $value_from_database . '"';
Will produce:
"my "escaped" value"
Which will break any normal string parser, so you need to do something like:
$value_from_database = 'my "escaped" value';
echo '"' . addslashes($value_from_database) . '"';
To produce:
"my \"escaped\" value"
However, if it were me I'd just target the double quote and escape:
$value_from_database = 'my "escaped" value';
echo '"' . str_replace('"', '\\"', $value_from_database) . '"';
I think you are mixing two problems. The first problem is SQL Injection and to prevent this you would have to escape the data going into the database. However by now there is a far more better way to do this. Using prepared statements and bound parameters. Example with PDO:
// setup a connection with the database
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// run query
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute(array(':name' => $name));
// get data
foreach ($stmt as $row) {
// do something with $row
}
The other thing you would have to worry about it XSS attacks which basically allows a possible attacker to inject code into your website. To prevent this you should always use htmlspecialchars() when displaying data with possible information you cannot trust:
echo htmlspecialchars($dataFromUnsafeSource, ENT_QUOTES, 'UTF-8');
All data is escaped when inserting into the database.
When using prepared statements and bound paramters this isn't needed anymore.
Should I use addslashes() then use str_replace() to change \" to "?
addslashes() sounds like a crappy way to prevent anything. So not needed AFAICT.
Another note about accessing the database and in the case you are still using the old mysql_* function:
They are no longer maintained and the community has begun the deprecation process. See the red box? Instead you should learn about prepared statements and use either PDO or MySQLi. If you can't decide, this article will help to choose. If you care to learn, here is a good PDO tutorial.
You should store data without modifying them.
You should perform the needed escaping when outputting the data or putting them "inside" other data, like inside a database query.
just use mysql_escape_string() instead of addslashes and ereg_replace as written in david walsh's blog.
just try it it'll be better. :)
My php script won't work if i try to insert into database something in Saxon genitive (for example value "mike's" won't be inserted).
PHP code is plain and simple:
"INSERT INTO cache (id,name,LinkID,number,TChecked) VALUES(".$idUser.",'".$LinkName."',".$LinkID.",".$number.",NOW());"
Everything works great until "$LinkaName" get some value with "special character". How to put values like "mike's", "won't" etc. into MySql database?
You need to escape these strings properly. In addition, the technique that you're using right now exposes you to an SQL injection attack.
The PHP docs for mysql_real_escape_string gives a good example of what you should do:
// Query
$query = sprintf("INSERT INTO cache (id,name,LinkID,number,TChecked) VALUES(%d,'%s',%d,%d,'%s');",
mysql_real_escape_string($idUser),
mysql_real_escape_string($LinkName),
mysql_real_escape_string($LinkID),
mysql_real_escape_string($number),
mysql_real_escape_string(NOW()));
You must escape them first, otherwise you generate an invalid query. The single quote matches the single quote at the start of the string.
$LinkName = mysql_real_escape_string($LinkName);
You can also use prepared statements to bind parameters to the query instead of concatenating and sending a string (use the PDO or mysqli libraries instead of the mysql lib).
You need to use mysql_real_escape_string() on those values.
Also make sure if you are not quoting those other variables, to cast them to integer (the only reason why you wouldn't quote them).
If you're using mysqli or PDO and not the standard extension, you can use a prepared statement instead of escaping.
I have a quick question about mysql_real_escape_string. Where should I use it?
I have a *.php file with form that is redirecting it to itself, but that file is using another file that has class in it with function Add(params);
So should I escape strings when they are submitted?
$catName = mysql_real_escape_string($_POST['edtCatAddName']);
Or should I escape strings in my class?
$catName = mysql_real_escape_string($catName);
Or perhaps both these situations are wrong and I need to do something else? I've tried to escape just my query like this
$query = mysql_real_escape_string("INSERT INTO cat (catName, catDescr, catImg, catSubLevel, catSubID) VALUES ('$catName', '$catDescr', '$catImgURL', $catSubLevel, $catSubID)");
But it's not too good because this way my query won't go since catName and some other variables are string type and I need to add ' before and after them and these chars are escaped.
Any advice? I'm very new to this...
So if I use PDO then all I have to do is
$STH = $DBH->prepare("my raw, not escaped query");
$STH->execute();
and I can feel secure?
nowhere, you should use PDO prepared statements instead to protect you against SQL-injections.
When to use mysql_real_escape_string()
Actually mysql_real_escape_string() is used while sanitize a input from a user. So you should (at least) use it everywhere a user can input anything that goes into a query. It is also very suggested to use Prepared Statements.
What Prepared Statements are
Basically they are sql queries that are very safe.
Let's make an example.
SELECT UserName FROM user WHERE UserUID = X
Is a simple query. Let's say that the X is a variable that come from a $_GET input. Some users could add to X everything. Even a 1; and then start a new query. This technique is called SQL Injection.
Now with mysql_real_escape_string() you solve part of this problem, and it's quite safe. But Prepared statements tell the server that
SELECT UserName FROM user WHERE UserUID =
Is something like a static part, and then that X is a variable. In this way the server is kinda prepared to execute such a query, and nothing else, considering any input in X like an input. In this way you have not to worry about user inputs at all.
you can do:
$catName = mysql_real_escape_string($_POST['catName']);
or use mysql_real_escape_string() directly in your query.
For values which are expected to be a number (integer, float) - you can either use intval($var) for integers or floatval($var) for floats.
BUT:
never use mysql_real_escape_string() for the entire query - that's simply wrong ;-)
EDIT:
I forgot to mention: the best is to use PDO(PHP Data Objects) -> http://de.php.net/PDO
Don't. Use parameters in queries using mysqli or PDO.
When inserting a row in mysql database, string values need to be enclosed in quotes where integer don't need to.
Is there any class or library that takes care of this automatically so that I can just pass to a 3rd-party function an array of fieldnames and values and don't have to worry about putting string values in quotes?
Thanks,
You need to worry about more than just quoting; you need to worry about SQL injection.
For new code, use PDO instead of the mysql_ or mysqli_ functions. Within PDO, use prepared statements (the PDOStatement object).
With prepared statements, you never have to enclose things in quotes and it stops SQL injections.
If you use PDO, then you do not need to worry about things like that.
Take a look at PDO::prepare for some examples.
When I'm using drupal, the default behavior of db_query("SELECT col FROM tab WHERE id=%d",$id) handles that for you.
This is similar to using sprintf with mysql_real_escape_string on your query first. And you could implement it yourself, from the code they show, note that they use the preg_replace_callback() method, and you can click on that..
The traditional way, if you ignore PDO (not recommended):
<?php
// Connect
$link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password')
OR die(mysql_error());
// Query
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
?>