So, members of my website can post topics, replies, comments, edit them and so on. I always use htmlspecialchars and addslashes for html inputs to protect my site against XSS and SQL injection attacks. Is it enough or is there something more I miss?
Thanks.
There is a lot that can go wrong with a web application. Other than XSS and SQLi, there is:
CSRF - Cross Site Request Forgery
LFI/RFI - Local File Include/Remote File Include caused by include(), require()...
CRLF injection in mail()
Global Variable Namespace Poising commonly caused by register_globals,extract(), import_request_variables()
Directory Traversal: fopen(), file_get_contents(), file_put_conents()
Remote Code Execution with eval() or preg_replace() with /e
Remote Code Execution with passthru(), exec(), system() and ``
There is a whole family of vulnerabilities regarding Broken Authentication and Session Management which is apart of the OWASP Top 10 that every web app programmer must read.
A Study In Scarlet is a good black paper that goes over many of these vulnerabilities that I have listed.
However, there are also strange vulnerabilities like this one in Wordpress. The definitive authority on what is a vulnerability is the CWE system which classifies HUNDREDS of vulnerabilities, many of which can affect web applications.
You should use prepared statements (see PDO) to prevent SQL injection. When outputting the content htmlspecialchars() seems sufficient to prevent XSS.
Also take a look at these links for more ways to protect your site:
http://phpsec.org/projects/guide/
http://cwe.mitre.org/top25/#Listing
http://www.owasp.org/index.php/Top_10_2010-Main
A better approach to protect against SQL injection is to use the escape function specifically written for each database - for example, for PostGreSQL use pg_escape_string to escape string fields before inserting them in to the database. Or in your case, use mysql_real_escape_string.
You should use mysql_real_escape_string() for SQL, not addslashes.
(Assuming you are using MySQL)
When inserting data into database, use prepared statements. PDO are better than mysql_real_espace_string.
When displaying data, such as comments, posts, use htmlentities.
SQL injection:
No addslashes nor mysql_real_escape_string could help alone. But only when used according some rules. And even then it's not enough. So, that's why prepared statements are way better for newbies - it require no thinking.
Both escaping and prepared statements can help with data only. For the operators/identifiers there are distinct rules. (Not a big deal though - every possible combination must be hardcoded in the script)
XSS:
Do not allow users to use HTML.
To prevent this, both strip_tags() (with no allowed tags) or htmlspecialchars() can be used.
If you want to allow some markup, consider a BB-code use.
CSRF:
Any significant form must contain an unique token, which should be compared to one, saved in the session.
Related
Possible Duplicate:
SQL injection that gets around mysql_real_escape_string()
I havent seen any valuabe or not outdated info on this.
So, there is this question: Does mysql_real_escape_string() FULLY protect against SQL injection? Yet it is very outdated(its from '09), so as of php 5.3 and mysql 5.5 in '12, does it protect fully ?
mysql_real_escape_string ALONE can prevent nothing.
Moreover, this function has nothing to do with injections at all.
Whenever you need escaping, you need it despite of "security", but just because it is required by SQL syntax. And where you don't need it, escaping won't help you even a bit.
The usage of this function is simple: when you have to use a quoted string in the query, you have to escape it's contents. Not because of some imaginary "malicious users", but merely to escape these quotes that were used to delimit a string. This is extremely simple rule, yet extremely mistaken by PHP folks.
This is just syntax related function, not security related.
Depending on this function in security matters, believing that it will "secure your database against malicious users" WILL lead you to injection.
A conclusion that you can make yourself:
No, this function is not enough.
Prepared statements is not a silver bullet too. It covers your back for only half of possible cases. See the important addition I made to the famous question for the details
long time since I read a blog post about this so it may no longer hold true BUT...
The posts stated that if you had unicode encoded characters in your string they would be missed by real escape string but would be evaluated by mysql engine - alluding to the idea that you could indeed still be open to a well placed injection.
I can't remember the blog post but this question on here is in the same ball-park.
Yes. By properly escaping the string using the native mysql escape functions, it's not possible to "break out" and execute a query.
However, a better approach would be to use prepared statements. This will do a number of things. By using prepared statements you take advantage of even more optimization from the database and it will properly escape any data passed in. Take a look at: http://php.net/manual/en/mysqli.prepare.php
I want to know how to prevent HTML injection. I have created a site where users are allowed to paste articles in a HTML form. I have used mysql_real_escape_sting but I want to know whether this is enough for preventing HTML injections. I tried htmlspecialchars but it’s showing error with mysql_real_escape_string.
No, mysql_real_escape_sting does only prepare data to be safely inserted into MySQL string declarations to prevent SQL injections in that specific context. It does not prevent other injections like HTML injection or Cross-Site Scripting (XSS).
Both HTML injection and XSS happen in different contexts where there are different contextual special characters that need to be taken care of. In HTML it’s especially <, >, &, ", and ' that delimit the different HTML contexts. With XSS in mind you also need to be aware of the different JavaScript contexts and their special characters.
htmlspecialchars should suffice the handle the former attack while json_encode can be used for a safe subset of JavaScript. See also the XSS (Cross Site Scripting) Prevention Cheat Sheet as well as my answer to Are these two functions overkill for sanitization? and related questions for further information on this topic.
You should use prepared statements to be absolutely sure to prevent sql injection.
Taken from documentation (read the part in bold)
Many of the more mature databases support the concept of prepared statements. What are they? They can be thought of as a kind of compiled template for the SQL that an application wants to run, that can be customized using variable parameters. Prepared statements offer two major benefits:
The query only needs to be parsed (or prepared) once, but can be
executed multiple times with the same or different parameters. When
the query is prepared, the database will analyze, compile and
optimize it's plan for executing the query. For complex queries this
process can take up enough time that it will noticeably slow down an
application if there is a need to repeat the same query many times
with different parameters. By using a prepared statement the
application avoids repeating the analyze/compile/optimize cycle. This
means that prepared statements use fewer resources and thus run
faster.
The parameters to prepared statements don't need to be quoted; the
driver automatically handles this. If an application exclusively uses
prepared statements, the developer can be sure that no SQL injection
will occur (however, if other portions of the query are being built
up with unescaped input, SQL injection is still possible).
Prepared statements are so useful that they are the only feature that PDO will emulate for drivers that don't support them. This ensures that an application will be able to use the same data access paradigm regardless of the capabilities of the database.
If you meant to prevent XSS (Cross site scripting) you should use the function htmlspecialchars() whenever you want to output something to the browser that came from user input or from any non secure source. Always treat any unknown source as unsecure
echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
No. In fact, I believe that for advanced coders, you shouldn't be using mysql_real_escape_string() as a crutch.
For each value you need to use in a DB query, seriously consider the possible characters that could appear. If it is a dollar amount, the only characters you should accept are numbers, a period, and possible preceding dollar sign. If it is a name, you should only allow letters, a hyphen, and possibly a period (for fulls names like Joseph A. Bank).
Once you determine a strict character range that's acceptable for a value, write a Regex to match that value against. For any values that don't match, display a bogus error and log the value in a textfile (read: not a db) along with the user's IP. Frequently check this file so you can see if values users have tried that didn't work were hacking attempts. Not only will this uncover valid inputs for which you need to adjust your Regex, but it will also reveal the IP's of hackers who try to find SQL vulnerabilities on your site.
This approach ensures that new and old SQL vulnerabilities that might not immediately be addressed by mysql_real_escape_string(), will be blocked.
No, it's not. Refer to the docs
It doesn't escape < or >.
Simple answer: No
mysql_real_escape_string only helps you get rid of SQL Injections and not XSS and html injection. To avoid these you need more sophisticated input validation. Start by looking at strip_tags and htmlentities.
I've read in several places that htmlspecialchars is not enough to prevent SQL injection attacks. I'm working with a legacy codebase and it uses this to sanitize user input:
stripslashes(htmlspecialchars(trim($value), ENT_QUOTES, 'UTF-8'))
My gut tells me that this is also unsafe but my coworker insists that it is. I don't have much experience in working with plain PHP so could someone please tell me why this is unsafe so that I can convince my coworker to use something better?
I've read in several places that htmlspecialchars is not enough to prevent SQL injection attacks
It protects against XSS attacks, but SQL is not HTML so it does nothing for SQL injection.
(You should move the htmlspecialchars encoding to "before inserting into HTML" instead of "before inserting into SQL")
My gut tells me that this is also unsafe but my coworker insists that it is.
Your gut is right. The fact it leaves quote characters alone shouts unsafe!.
Take a look at Bobby Tables. It demonstrates the problem and provides a number of solutions. Anything that uses bound parameters is good.
Use prepared statements.
disable magic quote in php.ini and use PDO. bum
htmlspecialchars to escape params in SQL is the ugliest
It may prevent you from XSS, but not from SQLi, because it doesn't quote any SQL-specific (or DBMS-specific) special characters. The most modern solution is to use PDO with Prepared Statement or PDO:quote(). Legacy solutions cover mysql_escape_string() and such. Refer the manual about the db-driver you are using, about the features it provides to prevent you from SQLi.
You should be calling a database specific escaping function on things you insert into queries.
For a MYSQL database, use mysql_real_escape_string.
It depends on the type of SQL query it is injecting. SQL injections in string fields (enclosed with ' and ") can be disabled by encoding or removing this characters. But in general this is not the solution!
You should NEVER EVER concatenate the SQL string together and send it to the database, especially if it contains user supplied data. You should always use the prepare statement to prepare a SQL statement with placeholders and then pass the parameters separately. Yes, this means that you will probably need to have more than one line of code and you will call corresponding SQL functions.
This is the only good solution for this that is implemented in all programming languages.
mysql_real_escape_string would be better than mysql_escape_string as it has been deprecated.
If my site ever goes live (don't think it will, its just a learning exercise at the moment).
I've been using mysql_real_escape_string(); on data from POST, SERVER and GET.
Also, I've been using intval(); on strings that must only be numbers.
I think this covers me from sql injection? Correct? Can i do more?
But, I'm not sure how it provides (if it provides any protection at all) from XSS injection?
Any more information on how to combat these two forms of attacks is appreciated.
I think this covers me from sql injection? Correct?
No. It makes a terrible mess of your data.
Can i do more?
Yes. You can protect your code from SQL injections.
Here is a brief explanation I've made already
Only I have to add that you should not spoil your source data arrays.
POST array has noting to do with SQL. The data may go into email, an HTML form, a file, online service, etc. Why treat it all with SQL protection?
On the other hand, you may take your data not from POST but from a file, online service, other query.
So, you have to protect not source arrays, but actual data that goes into query
Speaking of XSS, there are no simple universal rule again.
But in general, you have to use htmlspecialchars($data,ENT_QUOTES); for the every untrusted data you output as a text, and some other kinds of validations in some special cases, like filenames
Used hard coded prepared queries
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.