This question already has answers here:
How to include a PHP variable inside a MySQL statement
(5 answers)
Closed 3 years ago.
How do I escape quotes in PHP when trying to query a MySQL database?
Without adding addslashes on every value:
$fname = addslashes("Value's with quote''s'");
$lname = addslashes("Value's with quote''s'");
The proper way is using prepared statements, e.g. via PDO.
If you can't do that, you have to process all values which are passed into a database query with mysql_real_escape_string() - and no, doing that simply on all $_POST data is not an option since that would render them unusable for HTML output, etc. You could create a $_ESC or something similar though... but note that this variable will not be superglobal!
You ought to escape special characters (not only quotes) on every string value (it's useless to escape values you're not going to enclose in quotes in a query. Those values require another treatment).
To avoid boring repetitive typing you can apply an escaping function to array items in a loop.
In case you're using MySQL and for INSERT/UPDATE queries, you can use this helper function:
function dbSet($fields) {
$set = '';
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$set .= "`$field`='" . mysql_real_escape_string($_POST[$field]) . "', ";
}
}
return substr($set, 0, -2);
}
It is used like this:
$id = intval($_POST['id']);
$table = 'users';
$fields = explode(" ","name surname lastname address zip fax phone");
$query = "UPDATE `$table` SET ".dbSet($fields).", `date`=NOW() WHERE id=$id";
Also don't forget to set proper encoding using mysql_set_charset() as it's required for the mysql_real_escape_string() function.
A good idea would be using PDO prepared statements as described here.
It will automatically escape those characters.
Firstly, don't use addslashes() - it is not recommended for use with escaping DB query strings because it doesn't escape everything that actually needs to be escaped; there are some characters that can still get through.
The correct solution depends on the database you're using. Assuming you're using MySQL, the correct function to use instead of addslashes() is mysql_real_escape_string().
You probably notice that using this on every line is even more verbose than addslashes(), so it doesn't really answer your question.
If your fields are all separate variables (as per your example), then you're really stuck with doing that for a bunch of lines of code.
If you're using an array (eg $_POST), then you can do it in a loop, which will make things a lot neater - you can do things like this:
foreach($_POST as $key=>$value) {
$sqlstrings[$key]="`".$key"` = '".mysql_real_escape_string($value)."'";
}
$sql = "update table ".implode(' ',$sqlstrings)." where id=".$update_id;
A more up-to-date method for doing SQL is to use an object model rather than manually building the queries. PHP has a number of libraries that may help: mysqli is an improved MySQL library, and PDO is a database-neutral library. Either of these would give you much better security and flexibility than building the SQL code directly. However if you already have a lot of code in place then they would represent a fairly significant overhead of code changes, so you may want to go with the mysql_real_escape_string() option discussed above in the short term. I do recommend investating them them though.
Related
I know most people say to just use prepared statements, but I have a site with many existent queries and I need to sanitize the variables by the mysqli_real_escape_string() function method.
Also the php manual of mysqli_query() says mysqli_real_escape_string() is an acceptable alternative, so here I am ...
I want to do this type of queries:
$query = sprintf("SELECT * FROM users WHERE user_name = %s",
query_var($user_name, "text"));
$Records = mysqli_query($db, $query) or die(mysqli_error($db));
I want to know below function would work, I am unsure if:
I should still do the stripslashes() at the start ? An old function I used from Adobe Dreamweaver did this.
Is it OK to add the quotes like $the_value = "'".$the_value."'"; after the mysqli_real_escape_string() ?
Does it have any obvious / big flaws ?
I noticed the stripslashes() removes multiple \\\\\\ and replaces it with one, so that migt not work well for general use, e.g when a user submits a text comment or an item description that might contain \\\\, is it generally OK not to use stripslashes() here ?
I am mostly worried about SQL injections, it is OK if submitted data included html tags and so, I deal with that when outputing / printing data.
if(!function_exists('query_var')){
function query_var($the_value, $the_type="text"){
global $db;
// do I still need this ?
// $the_value = stripslashes($the_value);
$the_value = mysqli_real_escape_string($db, $the_value);
// do not allow dummy type of variables
if(!in_array($the_type, array('text', 'int', 'float', 'double'))){
$the_type='text';
}
if($the_type=='text'){
$the_value = "'".$the_value."'";
}
if($the_type=='int'){
$the_value = intval($the_value);
}
if($the_type == 'float' or $the_type=='double'){
$the_value = floatval($the_value);
}
return $the_value;
}
}
A text string constant in MySQL / MariaDB starts and ends with a single quote ' character. If the text itself contains a quote character, we escape it by doubling it. So the name "O'Leary" looks like this in a SQL statement's text.
SET surname = 'O''Leary'
That's the only rule. If your users feed you data with backslashes or other escaping schemes, you can feed it verbatim to MySql with the kind of text string representation mentioned here.
Don't overthink this. But use carefully debugged escaping functions. Avoid writing your own, because any tiny bug will allow SQL injection.
Looking at the PHP functions documentation, I found some references that made me decide the stripslashes() is not needed in that function.
https://www.php.net/manual/en/security.database.sql-injection.php
Generic functions like addslashes() are useful only in a very specific
environment (e.g. MySQL in a single-byte character set with disabled
NO_BACKSLASH_ESCAPES) so it is better to avoid them.
https://www.php.net/manual/en/function.addslashes.php
The addslashes() is sometimes incorrectly used to try to prevent SQL
Injection. Instead, database-specific escaping functions and/or
prepared statements should be used.
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 7 years ago.
I am beginning the process of coverting all of my MySQL to MySQLi.
I have been doing much research on this but find it a bit confusing.
I have two questions at this point regarding the matter:
1) What does it exactly mean to "escape" a string and where does the code for this go? I assume it goes on my page with my database login credentials.
I found the following but find it somewhat hard to interpret:
"We'll use the mysqli_real_escape_string() function. Since it needs a database connection, we'll go ahead and wrap it in its own function. In addition, since we only need to escape strings, we might as well quote the value at the same time:"
`
function db_quote($value) {
$connection = db_connect();
return "'" . mysqli_real_escape_string($connection,$value) . "'";
}
`
"If we are not sure of the type of value we pass to the database, it's always best to treat it as a string, escape and quote it. Let's look at a common example - form submission. We'll use our previous INSERT query with user input:"
`
// Quote and escape form submitted values
$name = db_quote($_POST['username']);
$email = db_quote($_POST['email']);
// Insert the values into the database
$result = db_query("INSERT INTO `users` (`name`,`email`) VALUES (" . $name . "," . $email . ")");
`
2) After I have this set up in my code, how do I properly test that it is indeed working (Without completly wiping out my tables, etc?)
I just really need some further explanations on this subject before I begin the process.
Any resources, advice, or pointers in the right direction would be greatly appreciated.
Escaping a string means converting characters that would be treated as special in a query as literal characters. A good example is a single quote. This has special meaning in a query, and attackers can use it to alter the functionality of the query to bypass security. Escaping that character makes it non-functional as part of the query such that it only contributes to a string value. Details on that can be found by studying SQL injection attacks.
As for where it goes, anytime you build a query with uncontrolled values, those values should be escaped.
**After I have this set up in my code, how do I properly test that it is indeed working (Without completly wiping out my tables, etc?)**
My preference is a combination of extracting the final query for manual testing, and extensive use of a test database so that the integrity of your production database isn't affected during development.
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. :)
Where and when do you use the quote method in PDO? I'm asking this in the light of the fact that in PDO, all quoting is done by the PDO object therefore no user input should be escaped/quoted etc. This makes one wonder why worry about a quote method if it's not gonna get used in a prepared statement anyway?
When using Prepared Statements with PDO::prepare() and PDOStatement::execute(), you don't have any quoting to do : this will be done automatically.
But, sometimes, you will not (or cannot) use prepared statements, and will have to write full SQL queries and execute them with PDO::exec() ; in those cases, you will have to make sure strings are quoted properly -- this is when the PDO::quote() method is useful.
While this may not be the only use-case it's the only one I've needed quote for. You can only pass values using PDO_Stmt::execute, so for example this query wouldn't work:
SELECT * FROM tbl WHERE :field = :value
quote comes in so that you can do this:
// Example: filter by a specific column
$columns = array("name", "location");
$column = isset($columns[$_GET["col"]]) ? $columns[$_GET["col"]] : $defaultCol;
$stmt = $pdo->prepare("SELECT * FROM tbl WHERE " . $pdo->quote($column) . " = :value");
$stmt->execute(array(":value" => $value));
$stmt = $pdo->prepare("SELECT * FROM tbl ORDER BY " . $pdo->quote($column) . " ASC");
and still expect $column to be filtered safely in the query.
The PDO system does not have (as far as I can find) any mechanism to bind an array variable in PHP into a set in SQL. That's a limitation of SQL prepared statements as well... thus you are left with the task of stitching together your own function for this purpose. For example, you have this:
$a = array(123, 'xyz', 789);
You want to end up with this:
$sql = "SELECT * FROM mytable WHERE item IN (123, 'xyz', 789)";
Using PDO::prepare() does not work because there's no method to bind the array variable $a into the set. You end up needing a loop where you individually quote each item in the array, then glue them together. In which case PDO::quote() is probably better than nothing, at least you get the character set details right.
Would be excellent if PDO supported a cleaner way to handle this. Don't forget, the empty set in SQL is a disgusting special case... which means any function you build for this purpose becomes more complex than you want it to be. Something like PDO::PARAM_SET as an option on the binding, with the individual driver deciding how to handle the empty set. Of course, that's no longer compatible with SQL prepared statements.
Happy if someone knows a way to avoid this difficulty.
A bit late anwser, but one situation where its useful is if you get a load of data out of your table which you're going to put back in later.
for example, i have a function which gets a load of text out of a table and writes it to a file. that text might later be inserted into another table. the quote() method makes all the quotes safe.
it's real easy:
$safeTextToFile = $DBH->quote($textFromDataBase);
I need to use a get function to retrieve $title variable from a url.
$title=$_GET["title"];
The $title is later used in a MySQL query.
The question is how to make this secure?
In other words, how to neutralize any malicious codes sent through the URL.
(For a value of "secure" equal to "to prevent it breaking the database"): use any database API that uses bound parameters.
Bound parmeters tend to let the database handle the escaping (so uses escaping routines written by the database authors rather then the language authors) and uses a syntax that is less prone to being forgotten about for that one vital escape then manually escaping each piece of input data with (for example) mysql_real_escape_string.
You might need to take other steps later before you do something with the data in a different context (e.g. to make it safe to insert into an HTML document)
You must use mysql_real_escape_string() to escape all characters that could interfere with you database. If you're displaying this title, you should also make use of htmlentities() or striptags()
As of PHP 5.2, you can use filter_input() and filter_input_array() to sanitize and validate the the $_GET or $_POST data.
For example:
$my_string = filter_input(INPUT_GET, 'my_string', FILTER_SANITIZE_STRING);
Read more about that in this article here.
For SQL queries, it's very recommended that you use PDO with prepared statements to protect from SQL injections. You can read about PDO in the PHP Manual here.
You can use mysql_real_escape_string function (Escapes special characters in a string for use in an SQL statement)
Php Manuel
Use query parameters. There is a number of different ways to connect to mysql from PHP, and they way to use parameters varies a little from framework to framework. Here is an example using PDO:
$dbh = new PDO('mysql:dbname=test;host=127.0.0.1', 'username', 'password');
$sth = $dbh->prepare("select * from table where title = :title")
$sth->execute(array(':title' => $_GET["title"]));
$rows = $sth->fetchAll();
var_dump($rows);