I am learning PDO after the many people telling me to do so. However in updating one of my scripts, PDO is causing me a problem that I'm not sure how to fix.
My problem is a user will input the title to the website. Say its "Smith's Inventory".
Since the whole PDO switch, it is saved in the db as "Smith\'s Inventory". Which is output in various places on my website. Such as the header, the html title, and the settings text box. If you click save again with \', then you get \\', and so on.
I realize why this is done, but how can it be fixed?
Here is the instert code:
foreach ($_POST as $key => $value)
{
$sql = $dbh->prepare("UPDATE settings set value=? where variable=?");
$sql->bindParam(1, $value);
$sql->bindParam(2, $key);
$sql->execute();
}
echo '<h2><font color=green>Saved</font></h2>';
Looks like you are double escaping the data.
The most likely reasons for this are:
Your PHP install has magic quotes enabled — best to turn them off
You are using something like mysql_real_escape_string and prepared statements with placeholders — use only the latter
I've had this problem before, it was due to PHP magic quotes. PHP automatically inserts a slash to escape 'risky' characters in order to prevent sql injection.
You need to either disabled magic quotes on your php install or use the stripstashes function just before you output it.
http://php.net/manual/en/security.magicquotes.disabling.php
http://php.net/manual/en/function.stripslashes.php
You can read about magic quotes here:
http://www.tizag.com/phpT/php-magic-quotes.php
You can use stripslashes on the PHP side.
<?php
$str = "Is your name O\'reilly?";
// Outputs: Is your name O'reilly?
echo stripslashes($str);
?>
Related
I have found from different blogs that it is strongly recommended to use htmlspecialchars() to output any data on screen to be safe from XSS Attack.
I am using filter_input() to filter any data that comes from user before inserting into database. filter_input() convert special characters like ' to ' and saved it that way,like
I'm going to shopping with Molly's sister;Dolly
.My question is
How can I print(output) apostrope or quotes and specific special characters to users screen using htmlspecialchars so that the output would be user friendly
I have tried to use htmlspecialchars($post,ENT_NOQUOTES);,but it gives me same copy of data that is stored in database.If I don't use htmlspecialchars(),just $post gives me expected result,which I think is vulnerable to XSS Attack
Thanks for your time,and look forward to get help from peers.
EDIT
I got suggestions to use htmlspecialchars_decode() or html_entity_decode() on answer,but
(https://stackoverflow.com/users/1338292/ja͢ck)
and some other suggested not to use these functions to output data on screen.
Please be informed that I am using prepared statement and parameterized query.But I don't want to keep any security holes,that's why filtering data before sending into database.
As I have used filter_input() to filter data before sending to database,is it safe to output data directly($post=$posted_data;) from database without using htmlspecialchars?
If I must need to use htmlspecialchars to output data,then how can I do it in this case?
Code Sample
$stmt1=mysqli_stmt_init($connect_dude);
/*Inserting into database*/
if(isset($_POST['titlex']) && isset($_POST['pricex']) && isset($_POST['detailx'])){
$tit=filter_input(INPUT_POST,'titlex',FILTER_SANITIZE_STRING);
$pri=preg_replace('#[^0-9]#','',$_POST['pricex']);
$det=filter_input(INPUT_POST,'detailx',FILTER_SANITIZE_STRING);
$query2="INSERT INTO `hotel1`.`dine` (user_id,title,price,detail) VALUES (?,?,?,?)";
mysqli_stmt_prepare($stmt1,$query2);
mysqli_stmt_bind_param($stmt1, "isis", $logged_id, $tit, $pri, $det);
mysqli_stmt_execute($stmt1);
}
/*Get Data from DB*/
$query1="SELECT id101,title,price,detail FROM `hotel1`.`dine` WHERE user_id=?";
mysqli_stmt_prepare($stmt1,$query1);
mysqli_stmt_bind_param($stmt1, "i", $user_idx);
mysqli_stmt_execute($stmt1);
mysqli_stmt_store_result($stmt1);
mysqli_stmt_bind_result($stmt1, $id101, $title,$price, $detail);
while(mysqli_stmt_fetch($stmt1)){
$id101=$id101;
$title=$title; //htmlspecialchars needed
$price=$price; //htmlspecialchars needed
$detail=$detail; //htmlspecialchars needed
........................
........................
}
I am using filter_input() to filter any data that comes from user before inserting into database.
This is a bad practice. Do not mangle your data before you insert it into a database. It's 2015; don't sanitize, use prepared statements instead.
$db = new \PDO(
'mysql:host=localhost;dbname=mydatabase;charset=UTF-8',
$username,
$password
);
// other stuff in between
$statement = $db->prepare(
"INSERT INTO yourtable (email, username) VALUES (:email, :username);"
);
$success = $statement->execute([
':email' => $_POST['email'],
':username' => $_POST['username']
]);
Prepared statements remove the need for filter_input(). You're not adding defense in depth by doing this, you're just ruining data integrity and giving yourself a headache.
When you render your output, if you want to allow HTML, use HTML Purifier.
Otherwise, use htmlspecialchars($output, ENT_QUOTES | ENT_HTML5, 'UTF-8') for best results.
Recommended Reading: Web Application Security by Taylor Hornby.
I think there's a problem with your strategy.
You certainly need to filter input and output stuff but you're overlaying them - double escape.
The problem is your input filter is doing also the output filter's work.
As I have used filter_input() to filter data before sending to database,is it safe to output data directly($post=$posted_data;) from database without using htmlspecialchars?
No. Don't trust your database, or at least not always. It wouldn't be the first case an SQL injection caused a huge XSS.
If I must need to use htmlspecialchars to output data,then how can I do it in this case?
As I said above, stop using input filter for output filtering. Your input filter should just make sure the data is safe for internal use - to protect your application against not-indented operations. Thus you don't need to escape HTML before inserting to database, and as a bonus you'll save space.
On the other hand output filter cares about the end-user. You take the data from db and send it to the user. We're talking about htmlspecialchars which is fine with ENT_QUOTES but in my opinion is not sufficient. You should also escape characters like ( ) [ ] = + - \ since there are cases you don't need for a successful XSS attack to open/end any tag or use quotes. For example when you output data into onclick, etc.
I just saw that htmlspecialchars has double_encode parameter, which would eventually solve your problem:
htmlspecialchars($string, ENT_QUOTES, "UTF-8", false);
Doing this will always keep HTML special chars escaped and won't escape already escaped stuff.
You want to go the other way around :) htmlspecialchars_decode()
You dont need to, when you encode them and save them to DB, they will be shown on the web page (when you use echo $result['message'];) as they should. Browsers automaticaly decode them.
I am using this function to strip input:
function stripinput($text) {
if (!is_array($text)) {
$text = trim($text);
$text = preg_replace("/(&)+(?=\#([0-9]{2,3});)/i", "&", $text);
$search = array("&", "\"", "'", "\\", '\"', "\'", "<", ">", " ");
$replace = array("&", """, "'", "\", """, "'", "<", ">", " ");
$text = str_replace($search, $replace, $text);
}else{
foreach ($text as $key => $value) {
$text[$key] = stripinput($value);
}
}
return $text;
}
I wasn't exactly sure how to word this, but essentially what I need is so when I send a SELECT query in MySQL, it doesn't pay attention to the escape character ( \ ) in the search. For example, if the name I am searching for is foo'bar and I send foo\'bar to the server, is there a way to make the server find foo'bar? This is the MySQL query currently:
function escape_data($data) {
$data = mysql_escape_string (trim($data));
$data = strip_tags($data);
return $data;
}
$champ1 = escape_data($_GET['champ1']);
foreach($db->query("SELECT * FROM champs WHERE name = '$champ1'") as $row) {
$role_verify_1 = $row[$role];
}
the only way I can get foo'bar to return is if I change it to foo\'bar in the MySQL database and I would like not to if it is possible.
The function you want is stripslashes before mysql_real_escape_string, however your real concern should be where the slashes are actually coming from - it looks like you might have magic quotes turned on. This is deprecated - check the link for instructions on disabling it.
The Syntax at PHP requires that.
For example;
name = '$champ1'
Here you have a variable in ' tags. But that variable includes ' inside like foo'bar, its turn to that.
name = 'foo'bar'
as you see php can't understand what is going on there. So it need to clear that problem like adding before ' an \. And inserted item will have slashes before aphostropes.
As a solution you can delete the backslashes before you echo the variable.
$theVariable = str_replace("\", "", $theVariable);
Or you can use PHP's upper version's functions. like stripslashes() before you insert your data.
Good luck.
I've written a blog system which works quite well, except for one little thing. I'm using a mysqli::real_escape_string to prevent the system from being exposed to SQL-injections. However, if someone writes a comment with a " or ' in it, these will be shown as \" or \', which isn't exactly user friendly.
Is there a way to prevent these from being written, or removing them before being echoed with PHP?
In your situation, escaping happen twice (probably because of the enabled settings "magic_quotes_gpc=On")
Example:
Is your name O'reilly?
When this parameter transmission browser (client) -> php (web-server) with magic_quotes_gpc = on
Is your name O\'reilly?
Then your code mysqli_real_escape_string
Is your name O\\\'reilly?
The result is stored in the table:
Is your name O\'reilly?
Сonclusion:
Outdated setting «magic_quotes_gpc» to disable.
NOTE. To prevent SQL-injection when the sql query is more expedient to use «prepared statements» in this case, the parameters do not require escaping.
So I was just testing out the mysql_real_escape(); function and what that does is puts a \ before the ". The when the content is echoed back out onto the page I just get content with \'s before any ". So let's say I posted """""""""""""""""""""""""""" all I get is \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\" echoed back.
Is there some code to remove the \ when it's echoed back onto the page?
By adding those slashes, mysql_real_escape_string just converts the string into the input format for the database. When the data comes out of the database, it should come out without any of the slashes. You shouldn't need to remove them yourself.
Using stripslashes like others are suggesting would do the opposite of mysql_real_escape_string in most cases, but not all of them, and you shouldn't rely on it for that purpose. Mind you, if you find yourself needing to use it for this, you've already done something else wrong.
stripslashes()
http://php.net/manual/en/function.stripslashes.php
You don't need to unescape, ie. remove the slashes - they don't get inserted into the DB. They are only for passing data to MySQL, they are not written to the db. When you SELECT the data, you won't see the slashes.
Do you know how mysql_real_escape() works. Hint: It allows to encode string for SQL usage. For example mysql_query('SELECT * FROM users WHERE name="'.mysql_real_escape_string($name).'"');. It can be used to insert string which won't escape the quotes for example like " or 1=1 -- " making SELECT * FROM users WHERE name="" or 1=1. You have to activate it just before inserting it database.
When you will read this data, slashes won't exist in any way.
Actually, looking at what is below, I will make this answer, not comment...
I am beginner in web development, I am developing a site that allows user to post various discussions and others comment and reply on it. The problem I am facing is, the user can post almost anything, including code snippets and any other thing which might possible include single quotes, double quotes and even some html content.
When such posts are being posted, it is intervening with the MySQL insert query as the quotes are ending the string and as a result the query is failing. And even when I display the string using php, the string is being interpreted as html by the browser, where as I want it to be interpreted as text. Do I have to parse the input string manually and escape all the special characters? or is there another way?
You need to read up on a few things
SQL Injection - What is SQL Injection and how to prevent it
PHP PDO - Using PHP PDO reduces the risk of injections
htmlentities
The basic premise is this, sanitize all input that is coming in and encode everything that is going out. Don't trust any user input.
If possible, whitelist instead of blacklisting.
EDIT :
I you want to display HTML or other code content in there, users need to mark those areas with the <pre> tag. Or you could use something like a markdown variation for formatting.
Use PDO, prepared statements and bound parameters to insert / update data, eg
$db = new PDO('mysql:host=hostname;dbname=dbname', 'user', 'pass');
$stmt = $db->prepare('INSERT INTO table (col1, col2) VALUES (?, ?)');
$stmt->execute(array('val1', 'val2'));
Edit: Please note, this is a very simplified example
When displaying data, filter it through htmlspecialchars(), eg
<?php echo htmlspecialchars($row['something'], ENT_COMPAT, 'UTF-8') ?>
Update
As noted on your comment to another answer, if you want to maintain indentation and white-space when displaying information in HTML, wrap the content in <pre> tags, eg
<pre><?php echo htmlspecialchars($data, ENT_COMPAT, 'UTF-8') ?></pre>
Look at mysql_real_escape_string and htmlentities functions in PHP manual.
You can also read the Security chapter in PHP manual.
To avoid the breaking of queries in database (which means you're not escaping them, leaving big holes for sql injection) you use mysql_real_escape_string($string) on the value before passing it to the query string, enclosing it in quotes also.
Ex. $value = mysql_real_escape_string($value); // be sure to have an open connection before using this function.
$query = "select * from `table` where value = '".$value."'";
As for displaying in html, you should at least echo htmlentities($string) before outputting it to the browser.
Like echo htmlentities($mystring, ENT_QUOTES)`;
Edit:
To preserve withe spaces, you can use nl2br function (which converts linebrakes to the html equivalen <br />) or go for a little deeper $string = nl2br(str_replace(" ", " ", $string));, but html code would look a bit ugly, at least for me
Reference: htmlentities and mysql_real_escape_string. nl2br
use mysql_real_escape_string. It is a good practice to use this on all user inputs to prevent SQL Injection attacks.