I have a textarea whose value will be inserted into a mysql database. To protect against a mysql injection, do I process the input through nl2br, mysql_real_escape_string, htmlentities, or a combination of 2 or all 3? In what order do I process the data?
nl2br basically converts all "\n" to "<br/>", so I don't see how it helps with sql injection (not mysql injection btw)
mysql_real_escape_string is usually used for this kind of thing.
htmlentities is used to prevent mishaps where users inject malicious <script> into your website if you allow user inputs. Note that it's usually an accepted practice to store string as is and only call htmlentities whenever you are outputting your string
You need to know what each of the above does and use them only when you need it, not combine them as they might break stuff even worse.
Another better and safer alternative for securing your database is to use mysqli http://sg.php.net/mysqli, it provides prepared statement to help you filter out your sql
The only processing you need upon insertion is mysql_real_escape_string, but it is preferred that you use prepared statements perhaps with PDO or MDB2.
Never store encoded data in a database. You should always store the raw data. That is, don't use nl2br or htmlentities for storage. You should, however, use it for display if the data is going to be inserted into the DOM (nl2br is purely visual, htmlentities will help protect against XSS). Also note that htmlspecialchars may be preferred depending upon how you want to handle the display -- this should be sufficient for basic XSS protection.
Remember this mantra:
Escape for storage
Encode for display
If you use prepared statements with PDO or mysqli then you simply bind the parameter. If using the old mysql extension then you should use mysql_real_escape_string().
Related
I'm new to creating websites using PHP, and I recently picked up a tip from a friend that if I escaped all of the data inputed from a form, then my website would be a lot less vulnerable to HTMLi and SQLi attacks. Let's say for example:
$_POST['name'] is equal to "<h1>You could have prevented this</h1>"
What will happen is on my website it will appear very large which is not good at all. I want it to display as
<h1>blabla</h1>
not
blabla
Is there a simple function for this?
It depends on where you're putting the data.
If you're echoing it into a HTML page, use something like htmlentities().
If you're putting it into a SQL string, use mysqli_escape_string() and/or use parameterized queries (mysqli's "prepare", or PDO).
If you're echoing it into a JavaScript fragment on a page, use something like json_encode().
The key point is that you need to use the right escaping function for what you're doing.
Use htmlentities() or htmlspecialchars() for when you output user input onto a page. This prevents XSS.
To prevent SQL Injection you should use a Prepared Statement (for example with PDO or MySQLi), not escaping. Escaping is a primitive way of preventing SQLi and it is not always 100% secure, unlike Prepared Statements which are (when used properly).
SQLi and XSS are different problems and should be solved separately. There is no one size fits all solution to prevent all types of vulnerabilities. Each type of vulnerability should be addressed individually.
Your "tip" makes little sense as HTML and SQL attacks are different things. Yet, if you want to avoid problems with display, use htmlspecialchars() or htmlentities() to escape such data. If you want to take care of SQLInjection, use mysqli_escape_string() or equivalent (PDO escapes automatically)
Is it totally safe to insert array serialized with serialize() into db, or I should do addslashes(serialize($array)) before? Or there can be some mysql specific characters? Can I delete data or whatever with insert?
No it is not safe at all.
And you should never use addslashes but mysql_real_escape_string instead. Or even better, use PDO with prepared statements instead of escaping.
It's totally ***un****safe* to insert the serialized data in the database without database-specific processing.
You should use whatever mechanism is recommended for preventing SQL injections with your chosen database access layer; making the queries safe against injections includes properly escaping the data as well, so you 'll hit two birds with one stone.
See How can I prevent SQL injection in PHP? for specific examples.
I am using mysql_real_escape_string to save content in my mySQL database. The content I save is HTML through a form. I delete and re-upload the PHP file that writes in DB when I need it.
To display correctly my HTML input I use stripslashes()
In other case, when I insert it without mysql_real_escape_string, I do not use stripslashes() on the output.
What is your opinion? Does stripslashes affect performance badly ?
Do not use stripslashes(). It is utterly useless in terms of security, and there's no added benefit. This practice came from the dark ages of "magic quotes", a thing of the past that has been eliminated in the next PHP version.
Instead, only filter input:
string: mysql_real_escape_string($data)
integers: (int)$data
floats: (float)$data
boolean: isset($data) && $data
The output is a different matter. If you are storing HTML, you need to filter HTML against javascript.
Edit: If you have to do stripslashes() for the output to look correctly, than most probably you have magic quotes turned on. Some CMS even made the grave mistake to do their own magic quotes (eg: Wordpress). Always filter as I advised above, turn off magic quotes, and you should be fine.
Do not think about performance, think about security. Use mysql_real_escape_string everytime you're inserting data into DB
No, don't escape it. Use prepared statements instead. Store your data in its raw format, and process it as necessary for display - for example, use a suitable method to prevent Javascript from executing when displaying user supplied HTML.
See Bill Karwin's Sql Injection Myths and Fallacies talk and slides for more information on this subject.
See HTML Purifier and htmlspecialchars for a couple of approaches to filter your HTML for output.
Check out a database abstraction library that does all this and more for you automatically, such as ADOdb at http://adodb.sourceforge.net/
It addresses a lot of the concerns others have brought up such as security / parameterization. I doubt any performance saved is worth the developer hassle to do all this manually every query, or the security practices sacrificed.
It is always best to scrub your data for potential malicious or overlooked special characters which might throw errors or corrupt your database.
Per PHP docs, it even says "If this function is not used to escape data, the query is vulnerable to SQL Injection Attacks."
What is the industry standard to filter input from users (both POST and GET) to avoid SQL injections and things of that nature. So far I am using filter_input() and mysql_real_escape_string() functions? Is that enough and if not, what other methods I should use?
An important rule to live by is FIEO. Filter Input Escape Output.
ANY information that you take and store from a user must be filtered server-side, in order to do this you should be using mysql_real_escape_string. It always should be the last thing you should before adding the value to the database. Validate the users input, ensure it is what you want, remove any symbols or tags if you need to using Regular Expressions, check its length and any other rules - do all this, then finally apply the MySQL function mysql_real_escape_string.
ANY information that you are displaying on your webpage that is dynamic - i.e. has come from a database of user-generated content or has directly come from user input must then be escaped. You must URL encode any symbols, remove (or encode) any HTML tags.
I highly recommend you watch this presentation on web security by expert Chris Shiflett:
http://www.slideshare.net/shiflett/evolution-of-web-security
Escaping to avoid SQL injection and filtering or validating inputs are two different things. You do not need to filter input to avoid SQL injection, and filtering input does not necessarily help against SQL injection.
To avoid SQL injection you escape the input so it won't mess up the syntax of your query, or you use prepared statements that avoid the problem entirely. It does not matter what this input contains, whether it's filtered or not. If you escape it once using the appropriate escaping function for your database or use prepared statements, you're done worrying about SQL injection.
You filter or validate input for different reasons, mostly because you do not want to allow certain values in the database. This is entirely separate from how these values are put into the database (which is where SQL injection could occur).
On output you need to escape the values according to your output medium as well, for the same reasons you escape them when putting them in an SQL query: to avoid messing up syntax, which may be exploited. I.e. when outputting to a webpage, you HTML escape your values. Again, it doesn't matter what value it is; if it's properly escaped, it can be anything.
i suggest you use database lib for saving data to database like pear db or cakephp orm
in this method you really sure noting can attack your db for injection
you may use PDO for database connection in php. PDO stands for PHP Data Object. It is better than mysql_connect. PDO is Objetc oriented and also it ensure much more protection.
http://www.php.net/manual/en/class.pdo.php
$link = new PDO ( $dsn, $user, $password, $options ) ;
use htmlspecialchars to encode characters that could cause problems. Validating the data is different, it depends on what you are expecting from the input field.
Is mysql_real_escape_string sufficient for cleaning user input in most situations?
::EDIT::
I'm thinking mostly in terms of preventing SQL injection but I ultimately want to know if I can trust user data after I apply mysql_real_escape_string or if I should take extra measures to clean the data before I pass it around the application and databases.
I see where cleaning for HTML chars is important but I wouldn't consider it necessary for trusting user input.
T
mysql_real_escape_string is not sufficient in all situations but it is definitely very good friend. The better solution is using Prepared Statements
//example from http://php.net/manual/en/pdo.prepared-statements.php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
Also, not to forget HTMLPurifier that can be used to discard any invalid/suspicious characters.
...........
Edit:
Based on the comments below, I need to post this link (I should have done before sorry for creating confusion)
mysql_real_escape_string() versus Prepared Statements
Quoting:
mysql_real_escape_string() prone to
the same kind of issues affecting
addslashes().
Chris Shiflett (Security Expert)
The answer to your question is No. mysql_real_escape_string() is not suitable for all user input and mysql_real_escape_string() does not stop all sql injection. addslashes() is another popular function to use in php, and it has the same problem.
vulnerable code:
mysql_query("select * from user where id=".mysql_real_escape_string($_GET[id]));
poc exploit:
http://localhost/sql_test.php?id=1 or sleep(500)
The patch is to use quote marks around id:
mysql_query("select * from user where id='".mysql_real_escape_string($_GET[id])."'");
Really the best approach is to use parametrized queries which a number of people ahve pointed out. Pdo works well, adodb is another popular library for php.
If you do use mysql_real_escape_string is should only be used for sql injection, and nothing else. Vulnerabilities are highly dependent on how the data is being used. One should apply security measures on a function by function basis. And yes, XSS is a VERY SERIOUS PROBLEM. Not filtering for html is a serious mistake that a hacker will use to pw3n you. Please read the xss faq.
To the database, yes. You'll want to consider adequately escaping / encoding data for output as well.
You should also consider validating the input against what you expect it to be.
Have you considered using prepared statements? PHP offers numerous ways to interact with your database. Most of which are better than the mysql_* functions.
PDO, MDB2 and the MySQL Improved should get you started.
What situations?
For SQL queries, it's great. (Prepared statements are better - I vote PDO for this - but the function escapes just fine.) For HTML and the like, it is not the tool for the job - try a generic htmlspecialchars or a more precise tool like HTML Purifier.
To address the edit: The only other layer you could add is data valdation, e.g. confirm that if you are putting an integer into the database, and you are expecting a positive integer, you return an error to the user on attempting to put in a negative integer. As far as data integrity is concerned, mysql_real_escape_string is the best you have for escaping (though, again, prepared statements are a cleaner system that avoids escaping entirely).
mysql_real_escape_string() is useful for preventing SQL injection attacks only. It won't help you with preventing cross site scripting attacks. For that, you should use htmlspecialchars() just before outputting data that was originally collected from user input.
There are two ways, one is to use prepared statements (as mentioned in other answers), but that will slow down your app, because you now have to send two requests to the Database, instead of one. If you can live with the reduced performance, then go for it; Prepared Statements makes your code prettier and easier to deal with.
If you chose to use mysql_real_escape_string, then make sure that you escape all the strings that are untrusted. An (mysql_real_escape_string) escaped string is SQL Injection secure. If you don't escape all the strings, then you are not secure. You should really combine mysql_real_escape_string with input validation; checking that a variable you expect to hold a number really is a number and within the expected range. Remember, never trust the user.
There are different types of "cleaning".
mysql_real_escape_string is sufficient for database data, but will still be evaluated by the browser upon display if it is HTML.
To remove HTML from user input, you can use strip_tags.
I would suggest you look into using PDO instead of regular MySQL stuff, as it supports prepared statements right out of the box, and those handle the escaping of invalid data for you.
You can try both, as in
function clean_input($instr) {
// Note that PHP performs addslashes() on GET/POST data.
// Avoid double escaping by checking the setting before doing this.
if(get_magic_quotes_gpc()) {
$str = stripslashes($instr);
}
return mysql_real_escape_string(strip_tags(trim($instr)));
}
The best way to go would be to use Prepared Statements
I thought I'd add that PHP 5.2+ has input filter functions that can sanitize user input in a variety of ways.
Here's the manual entry as well as a blog post [by Matt Butcher] about why they're great.