Should I disallow characters like ",',>,<,\ ... to be typed in an upload forms text field? The text will be send through PHP to a blog.
I heared that some characters might cause trouble and could be used to "hack / harm" servers. Which characters should be restricted?
Thanks for your input.
Michael
There is no need to restrict anything. The problem is that you have to sanitize all user input; for this specific type of data (possible HTML) it is necessary and enough to use htmlspecialchars on all user-provided data before displaying it as part of your page.
For example, if your form has a textarea named post-body, you should receive the user input (e.g. with $_REQUEST['post-body']) and save it to your database as-is (warning: use mysql_real_escape_string or PDO to protect yourself from SQL injection at this stage!). When the time comes to display it, you would retrieve it from the database and print it with something like
echo htmlspecialchars($postBody);
See this question for some more background on data sanitization.
Users data should be sanitized by htmlspecialchars function each time when you output users data, to avoid XSS-attacks.
Also, to work with users data in sql-queries, use PDO and prepared statements or mysql_real_escape_string function to avoid SQL-injection. Example.
<? $string = str_replace("\\\"", "\"", $string);
$string = htmlspecialchars($string);
$string = preg_replace( "/\r\n|\n|\r/", "<br>", $string ); ?>
<input type = "text" name = "string" id = "string" value = "<?=$string?>">
Related
I want to post data into database in safe mode.
For example if i want to add this title to database:
$title = " here is title 'here is title' here is title ";
notice it has apostrophes.
I use this function to make string safe:
function stringsafe($string)
{
$string = strip_tags(trim(addslashes($string)));
return $string;
}
as you see it's adding slashes before apostrophes to make it safe.
I tried to remove slashes when i show the data by stripslashes, it's working but it's has some problems. Is there anyway to post data into database?
On a side note, in fact the general rules of thumb is that, you shouldn't alter user input at all. You should store whatever user input as it is, into your database, so that you can retain user input as original as possible, and only escape it when you need to display or use it.
In your case, yes you are right you have to prevent it from being injected, but you are altering the original input by adding slashes into the original input, which is not very favoured. What if my title contains a string like this <My 21st Birthday Party!> and you stripped it away?
Try using Prepared Statements instead so you can insert any data into your database, without the worries of injection. And only when you need the data to be displayed on a HTML page or console, you escape them accordingly such as htmlentities.
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;
}
From a form, I'm asking the user to enter some text. I will retrieve this text using $_POST['text'].
The user enters the string "It's my text!"
$newText = mysql_real_escape_string($_POST['text']);
Now on the very same page after I've inserted $newText into the database I want to display
the text to the user and also use it as the value of an input text box using PHP.
// I want to make sure the user hasn't added any unsafe html in their string
$newText = htmlentities($newText);
echo "You've entered: " . $newText . "<br />";
echo "<form action=someaction.php method=post>";
echo "<input type=text value=\"" . $newText . "\">";
echo "</form>";
The output is:
You've entered: It\'s my text!
[It\'s my text!]
How do I avoid these slashes, and should I be doing anything else with my data?
You're passing the text through mysql_real_escape_string() which, as the name suggests, escapes the string, including apostrophes. mysql_real_escape_string() is meant only for preparing the data for saving to database. You shouldn't use it when displaying data to the user.
So, the solution is simple: remove the line and use htmlentities() only. Use mysql_real_escape_string() when you're saving the string to database (and only then).
Only use mysql_real_escape_string() on the variable you want to use in the query, because it will add slashes to escape some of the characters in the string. This works great for mysql, but when want to use it on the page it will look weird.
You could make 2 variables, 1 for MySQL and 1 for displaying the raw text.
$text = $_POST['text'];
$db_text = mysql_real_escape($text);
Also note that you should use strip_slashes() on the data you get from the database later, to remove the slashes.
Hope this clear things up a little bit.
Now on the very same page after I've inserted $newText into the database I want to display the text to the user
That's what you are doing wrong.
An HTTP standard require a GET method redirect after every successful POST request.
So, you have to redirect the user on the same page, where you may read inserted data from the database and show it to the user.
As for the mistake you made - just move escaping somewhere closer to the database operations, to make sure it is used only for the purpose (YET it is used obligatory, without the risk of forgetting it!).
Ideally you have to use some variables to represent the data in the query, and some handler to process them.
So, the query call may look like
DB::run("UPDATE table SET text=s:text",$_POST['text']);
where s:text is such a variable (called placeholder), which will be substituted with the $_POST['text'] value, properly prepared according to the type set in the placeholder name (s means "string", tells your function to escape and quote the data)
So, all the necessary preparations will be done inside and will spoil no source variable.
save normally using mysql_real_escape_string()
and when you want to display it in a form:
htmlspecialchars(stripslashes($row['text_data']))
it will do the trick.
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.
I normally use this function to sanitize my form inputs before storing them into my database:
//Function to sanitize values received from the form. Prevents SQL injection
function clean($str) {
$str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return mysql_real_escape_string($str);
}
Until today I didn't realize that mysql_real_escape_string required a database connection as I've only used it when I've been cleaning the data before storing it into the database.
I tried using the function on a contact form and got the "A link to the server could not be established" error. I could connect to the database but there is no need because I simply am trying to sanitize the data before it's being sent out to my e-mail via the contact form.
What is the best way to sanitize data that's not being stored in a mysql database and does this data still need to be sanitized?
use filter_var()
http://php.net/manual/en/function.filter-var.php
like if you want to sanitize an email:
$_POST['email'] = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
to message
$_POST['message'] = filter_var($_POST['message'], FILTER_SANITIZE_STRING);
is enogth
The purpose of sanitizing the data with mysql_real_escape_string is to avoid SQL injection. If you're not using SQL, you're already immune.
Men don't get cervical cancer.
Use a sanitization function appropriate to the special characters you need to avoid. Ideally, don't strip something which won't cause harm.
The whole concept is wrong.
This function doesn't help not for email not even for database.
mysql_real_escape_string do not "sanitize" anything. It is merely escape delimiters and nothing else. Just to prevent syntax errors if you have a delimiter in your data:
SELECT * FROM table WHERE name = 'it's me' # error!
after data being escaped, your data become 'it\'s me' and there is no error.
Therefore, this function works only with SQL query and for data, enclosed in quotes only.
Thus, there is no sense in doing just mysql_real_escape_string without having quotes around. mysql_real_escape_string should be used
a) alone. stuff like trim or stripslashes has nothing to do here
b) right before query string composing and not elsewhere
c) only with data that going to be enclosed in quotes.
d) all other data need another ways of sanitization
As for the email, you don't need any sanitization it you send it as plain text.
The only precaution you have to take is against mail injection
Not a big deal though. Just put user input into message body only. not into subject, to or from or any other header. Message body only. And you are safe
(I'm new to stackoverflow so I'm going about this the wrong way/doing a bad job with the styling of my answer feel free to let me know.)
Correct me if I'm wrong as I'm also dealing with the same issue right now, but I don't think that the accepted answer using filter_var is enough as attackers could bypass this using unicode.
Example: "& #66;& #99;& #99;& #58;" (spaces added so stackoverflow will display it correctly)
This wouldn't get removed from the string, and would later be replaced with "Bcc:".
This is my solution, but there may be a better way. If anyone knows of one I'd love to hear it.
$string = str_replace("&", "(and)", $string);
$string = str_replace("#", "(num)", $string);
$string = str_replace(";", "(semi-colon)", $string);
$string = str_replace(":", "(colon)", $string);
$string = str_replace("#", "(at)", $string);
$string = str_replace("\\", "(backslash)", $string);
$string = filter_var($string, FILTER_SANITIZE_STRING);