I'm using mysqli prepared statements. Should I still sanitise the user input with some function like:
function sanitise($string){
$string = strip_tags($string); // Remove HTML
$string = htmlspecialchars($string); // Convert characters
$string = trim(rtrim(ltrim($string))); // Remove spaces
$string = mysql_real_escape_string($string); // Prevent SQL Injection
return $string;
}
Thanks.
No! No and no. If you are already using prepared statements, MySQL needs to see the value, not some escaped version of it. If you add mysql_real_escape_string to a string and make that the value for a prepared statement, you have just junked it, for example, quotes get doubled up!
Now, as for sanitising data-wise, that's entirely up to the business rules as to what is or is not valid input. In your example, strip_tags is more about html->raw (format) conversion than sanitation. So is rtrim(ltrim - this is a business transformation.
Yes. When using prepared statements you are safe from mysql injections, but still there could be special characters, strip tags or spaces, so those you will still need to take care of those.
See PHP: Is mysql_real_escape_string sufficient for cleaning user input?
UPDATE:
You are safe from mysql injections so you should not use real_mysql_scape_string or scape any quotes.
Prepared statements are there to keep your query form being subverted by malicious input. But there's plenty of malicious content that is perfectly acceptable in an SQL query, but will attack a browser when redisplayed later.
Doing mysql_real_escape_string on data going into a prepared statement is generally redundant (there are exceptions, but they're special-ish cases).
Here is an Object orientated solution to your question:
public function sanitize($var){
if(is_array($var))
foreach($var as $k => $v) $var[$k] = $this->db->real_escape_string($v);
else
$var = $this->db->real_escape_string($var);
return $var;
}
You should always sanitize your user inputs before submitting them to the database. I would just stick with mysql_real_escape_string as the others are not that much necessary unless you are putting them back on the URL.
Related
I've been working on a code that escapes your posts if they are strings before you enter them in DB, is it an good idea? Here is the code: (Updated to numeric)
static function securePosts(){
$posts = array();
foreach($_POST as $key => $val){
if(!is_numeric($val)){
if(is_string($val)){
if(get_magic_quotes_gpc())
$val = stripslashes($val);
$posts[$key] = mysql_real_escape_string($val);
}
}else
$posts[$key] = $val;
}
return $posts;
}
Then in an other file:
if(isset($_POST)){
$post = ChangeHandler::securePosts();
if(isset($post['user'])){
AddUserToDbOrWhatEver($post['user']);
}
}
Is this good or will it have bad effects when escaping before even entering it in the function (addtodborwhater)
When working with user-input, one should distinguish between validation and escaping.
Validation
There you test the content of the user-input. If you expect a number, you check if this is really a numerical input. Validation can be done as early as possible. If the validation fails, you can reject it immediately and return with an error message.
Escaping
Here you bring the user-input into a form, that can not damage a given target system. Escaping should be done as late as possible and only for the given system. If you want to store the user-input into a database, you would use a function like mysqli_real_escape_string() or a parameterized PDO query. Later if you want to output it on an HTML page you would use htmlspecialchars().
It's not a good idea to preventive escape the user-input, or to escape it for several target systems. Each escaping can corrupt the original value for other target systems, you can loose information this way.
P.S.
As YourCommonSense correctly pointed out, it is not always enough to use escape functions to be safe, but that does not mean that you should not use them. Often the character encoding is a pitfall for security efforts, and it is a good habit to declare the character encoding explicitely. In the case of mysqli this can be done with $db->set_charset('utf8'); and for HTML pages it helps to declare the charset with a meta tag.
It is ALWAYS a good idea to escape user input BEFORE inserting anything in database. However, you should also try to convert values, that you expect to be a number to integers (signed or unsigned). Or better - you should use prepared SQL statements. There is a lot of info of the latter here and on PHP docs.
I just read about SQL injection and found this function on the blog i was reading
I am wondering if it is safe for SQL injection.. say if i pass do remove_mq($_POST) to it, could i be using $_POST["var"] inside a query without a problem?
function remove_mq($array){
foreach($array as $key => $value){
if(is_array($value)){
$array[$key] = remove_mq($value);
}
else{
$array[$key] = addslashes($value);
}
}
return $array;
}
No. Addslashes is not the proper function to escape for a query. You need to use mysql_real_escape_string
Besides that, you should not perform SQL escaping before actually using a value in a query. Assume you have something like <input name="foo" value="$_POST[foo]" - then you need it htmlspecialchars()-escaped and not addslashes(etc.)-escaped
Besides that, the best solution would be using PDO with prepared statements since you separate SQL queries from params so you do not need any escaping at all.
Best practice nowadays is prepared queries.
Example:
$stmt = $pdo->prepare('SELECT username FROM users WHERE id = :id');
$stmt->execute(array(':id' => $_GET['id']));
$result = $stmt->fetchAll();
This code is totally secure
Well, all the answers above missing the point.
addslashes() is good enough as long as your data encoding is either utf-8 or any single-byte one.
but the whole approach, despite of the function used, is utterly wrong
Doing massive escaping over $_POST makes no sense and doesn't guarantee full protection.
No addslashes nor mysql_real_escape_string do any actual protection. It does as little as string delimiters escaping. So, you have to use this function:
only on strings
only on strings actually going into query.
all other required manipulations are described in the link in the comments
and some info for ones who feel extremely educated in the matter:
your beloved PDO, when used out of the box, do use the same defamed addslashes
Nope - just use the built in function for it! mysql_real_escape_string() is always going to be more reliable than any function you can write yourself.
Here's an article explaining why you should use mysql_real_escape_string over addslashes.
Of course, the best approach is to use prepared queries. Here's some information on them.
I am creating a function for my $_POST inputs to prevent SQL Injection BEFORE adding the values into database. I use it on login/register and when a user needs to post an article. As far as I know, this does not secure it from XSS.
Should I create a different function when I output data or edit this?
Thank you.
function clean($str) {
$str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return mysql_real_escape_string($str);
}
Try using prepared statements. They are designed to automatically escape things. They should also keep your queries cleaner in the source code.
http://www.ultramegatech.com/blog/2009/07/using-mysql-prepared-statements-in-php/
http://php.net/manual/en/mysqli.prepare.php
http://php.net/manual/en/book.pdo.php
You talk about XSS and then SQL injection...
SQL
Use mysql_real_escape_string() or better still bind params with a library such as PDO.
If magic_quotes is a possibility, use...
function sqlEscape($str) {
if (get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return mysql_real_escape_string($str);
}
Regarding your example, why do you need to use trim() to make data safe? Also, why use the error supressor on trim()?
XSS
Use htmlspecialchars($str, ENT_QUOTES) to prevent HTML special characters from having special meaning.
I use the following, which works just fine to prevent injections:
function clean($str) {
$value = mysql_escape_string(stripslashes(htmlspecialchars($str)));
return $value;
}
You shouldn't save values as encoded HTML to your database. Do that when outputting them, not when saving them (saving encoded HTML makes it harder to search in it, makes their size bigger, makes it harder to use them in formats other than HTML and generally just wrong - your database should store the actual text, not the text formatted to be displayed in a specific way).
Also, as Quamis said, you should probably look at PDO or some other DBAL that lets you use prepared statements instead of escaping it manually.
I am tring to make my PHP as secure as possible, and the two main things I am trying to avoid are
mySQL Injections
Cross-Side Scripting (XSS)
This is the script I got against mySQL Injections:
function make_safe($variable) {
$variable = mysql_real_escape_string(trim($variable));
return $variable; }
http://www.addedbytes.com/writing-secure-php/writing-secure-php-1/
Against XSS, I found this:
$username = strip_tags($_POST['username']);
Now I want to unite the two into a single function. Would this be the best way to do so? :
function make_safe($variable) {
$variable = strip_tags(mysql_real_escape_string(trim($variable)));
return $variable; }
Or does the mysql_real_escape_string already prevent XSS? And lastly, is there anything else that I could add into this function to prevent other forms of hacking?
mysql_real_escape_string() doesn't prevent XSS. It will only make impossible to do SQL injections.
To fight XSS, you need to use htmlspecialchars() or strip_tags(). 1st will convert special chars like < to < that will show up as <, but won't be executed. 2nd just strip all tags out.
I don't recommend to make special function to do it or even make one function to do it all, but your given example would work. I assume.
This function:
function make_safe($variable)
{
$variable = strip_tags(mysql_real_escape_string(trim($variable)));
return $variable;
}
Will not work
SQL injection and XSS are two different beasts. Because they each require different escaping you need to use each escape function strip_tags and mysql_real_escape_string separatly.
Joining them up will defeat the security of each.
Use the standard mysql_real_escape_string() when inputting data into the database.
Use strip_tags() when querying stuff out of the database before outputting them to the screen.
Why combining the two function is dangerous
From the horses mouth: http://php.net/manual/en/function.strip-tags.php
Because strip_tags() does not actually validate the HTML, partial or broken tags can result in the removal of more text/data than expected.
So by inputting malformed html into a database field a smart attacker can use your naive implementation to defeat mysql_real_escape_string() in your combo.
What you should really be looking into is using prepared statements and PDO to both provide an abstraction layer against your database as well as completely eradicate SQL injection attacks.
As for XSS, just make sure to never trust user input. Either run strip_tags or htmlentities when you store the data, or when you output it (not both as this will mess with your output), and you'll be all right.
Question: Is preventing XSS (cross-site scripting) as simple using strip_tags on any saved input fields and running htmlspecialchars on any displayed output ... and preventing SQL Injection by using PHP PDO prepared statements?
Here's an example:
// INPUT: Input a persons favorite color and save to database
// this should prevent SQL injection ( by using prepared statement)
// and help prevent XSS (by using strip_tags)
$sql = 'INSERT INTO TABLE favorite (person_name, color) VALUES (?,?)';
$sth = $conn->prepare($sql);
$sth->execute(array(strip_tags($_POST['person_name']), strip_tags($_POST['color'])));
// OUTPUT: Output a persons favorite color from the database
// this should prevent XSS (by using htmlspecialchars) when displaying
$sql = 'SELECT color FROM favorite WHERE person_name = ?';
$sth = $conn->prepare($sql);
$sth->execute(array(strip_tags($_POST['person_name'])));
$sth->setFetchMode(PDO::FETCH_BOTH);
while($color = $sth->fetch()){
echo htmlspecialchars($color, ENT_QUOTES, 'UTF-8');
}
It's even more simple. Just htmlspecialchars() (with quote style and character set) on user-controlled input is enough. The strip_tags() is only useful if you already want to sanitize data prior to processing/save in database, which is often not used in real world. HTML code doesn't harm in PHP source, but PHP code may do so if you use eval() on non-sanitized user-controlled input or that kind of evil stuff.
This however doesn't save you from SQL injections, but that's another story.
Update: to get clean user input from the request to avoid magic quotes in user-controlled input, you can use the following function:
function get_string($array, $index, $default = null) {
if (isset($array[$index]) && strlen($value = trim($array[$index])) > 0) {
return get_magic_quotes_gpc() ? stripslashes($value) : $value;
} else {
return $default;
}
}
which can be used as:
$username = get_string($_POST, "username");
$password = get_string($_POST, "password");
(you can do simliar for get_number, get_boolean, get_array, etc)
To prepare the SQL query to avoid SQL injections, do:
$sql = sprintf(
"SELECT id FROM user WHERE username = '%s' AND password = MD5('%s')",
mysql_real_escape_string($user),
mysql_real_escape_string($password)
);
To display user-controlled input to avoid XSS, do:
echo htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
It depends on where and how you want to use the user data. You need to know the context you want to insert your data in and the meta characters of that context.
If you just want to allow the user to put text up on your website, htmlspecialchars suffices to escape the HTML meta characters. But if you want to allow certain HTML or want to embed user data in existing HTML elements (like a URL into a A/IMG element), htmlspecialchars is not enough as you’re not in the HTML context anymore but in the URL context.
So entering <script>alert("xss")</script> into a image URL field will yield:
<img src="<script>alert("xss")</script>" />
But entering javascript:alert("xss") will succeed:
<img src="javascript:alert("xss")" />
Here you should take a look at the fabulous XSS (Cross Site Scripting) Cheat Sheet to see what contexts your user data can be injected in.
strip_tags is not necessary. In most cases strip_tags is just irritating, because some of your users may want to use < and > in their texts. Just use htmlspecialchars (or htmlentities if you prefer) before you echo the texts to the browser.
(Don't forget mysql_real_esacpe_string before you insert anything into your database!)
The general rule/meme is "Filter Input, Escape Output." Using strip_tags on your input to remove any HTML is a good idea for input filtering, but you should be as strict as possible in what input you allow. For example, if an input parameter is only supposed to be an integer, only accept numeric input and always convert it to an integer before doing anything with it. A well-vetted input filtering library is going to help you a lot here; one that isn't specific to a particular framework is Inspekt (which I wrote, so I'm a bit biased).
For output, htmlspecialchars should be able to escape XSS attacks, but only if you pass the correct parameters. You must pass the quote escaping style and a charset.
In general, this should remove XSS attacks:
$safer_str = htmlspecialchars($unsafe_str, ENT_QUOTES, 'UTF-8');
Without passing ENT_QUOTES as the second parameter, single-quote chars are not encoded. Additionally, XSS attacks have been demonstrated when the correct charset is not passed (typically UTF-8 will be adequate). htmlspecialchars should always be called with ENT_QUOTES and a charset parameter.
Note that PHP 5.2.12 contains a fix for a multibyte XSS attack.
You may find the OWASP ESAPI PHP port interesting and useful, although the PHP version is not complete AFAIK.
Yes, using PDO prepared statements protects from SQL injection. The SQL injection attack is based on the fact that the data submitted by the attacker is treated as a part of the query. For example, the attacker submits the string "a' or 'a'='a" as his password. Instead of the whole string being compared to the passwords in the database, it is included in the query, so the query becomes "SELECT * FROM users WHERE login='joe' AND password='a' or 'a'='a'". The part of attacker input is interpreted as a part of the query. However in case of prepared statements, you are telling the SQL engine specifically, what part is the query, and what part is data (by setting the parameters), so no such confusion is possible.
No, using strip_tags will not always protect you from cross-site scripting. Consider the following example. Let's say your page contains:
<script>
location.href='newpage_<?php echo strip_tags($_GET['language']); ?>.html';
</script>
The attacker submits the request with "language" set to "';somethingevil();'" . strip_tags() returns this data as is (there are no tags in it). The produced page code becomes:
<script>
location.href='newpage_';somethingevil();'.html';
</script>
somethingevil() gets executed. Replace somethingevil() with actual XSS exploit code.
Your last example with htmlspecialchars() will protect against this one, because it will escape single quotes. However I have seen even weirder cases of user-supplied data inside JavaScript code, where it is not even within a quoted string. I think it was in the variable or function name. In that last case no amount of escaping will probably help. I beleive that it is best to avoid using user input to generate JavaScript code.
Simple answer : no
Longer answer : There are ways to inject xss that PHP strip_stags cannot avoid.
For better protection try HTML purifier