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.
Related
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 8 years ago.
First of all, let's get one thing straight, while im sure it's not the ONLY solution to sql injections, PREPARED STATEMENTS ARE BETTER and MORE SECURE... that's granted.
So let's not debate it anymore, as I just needed to explore the escaping options and target the user inputs rather than the statement..
(a bit of back story)
I have a huge application w/ lots of basic SQL statements which i need to make "safer" in a short period of time. Converting all statements to PDO is a monster of a task which requires resources not available to this situation.
But good thing is that there's a hook in the application where ALL incoming $_GET/$_POST passes through a function before making available as plain variable in the scripts... ( eg.globalize($_POST) )
So i'm looking to target that function instead and focus on "cleaning" user input ...
I pretty much got a good grasp of SQL injection techniques, and basically much of its concept, such as:
1) Whenever there is user input involved in a statement, that's when the attacker has an opportunity
2) The main mission is to break your statement's quoting by simple single or double quotes as string, or character codes, in the attacker's input..
3) Escaping is good at preventing SQL injections except for that situation when the DATABASE character encoding is able to ready multibyte representations of those nasty illegal strings and the script based escaping misses it.
Based on the above premise, what if:
1) All my SQL Statements follow a standard where user input is quoted using single quotes ALWAYS, therefore there is no guess work for me anymore on what type of quote i need to escape (single quotes)
2) all user inputs (POST / GET) go through a function (eg. globalize() ) that basically addslashes() and globalizes each variable
3) This is an intranet application and the scripts can be made aware of the database encoding support.
QUESTION:
What are the threats currently available in the above situation and how can we handle them?
...i personally was looking into simply adding routines to the globalize() function similar to mysql_real_escape_string() .. or go as far as "tweaking" the SQL statements to use mysql_real_escape_string() as that is a lot easier/faster to do than programming statements on each sql query..
PS
Of course this script may never be as secure as prepared statements, but i just need to make it hard enough for most attackers (not looking to 100% bullet proof it as it is not that worth it)
Using
mysql_real_escape_string($link,$non_escaped_string);
See here: http://php.net/manual/en/mysqli.real-escape-string.php
While it might well work, there are a few possible issues.
If you use addslashes then there are potential exploits, hence for MySQL mysql_real_escape_string() is generally better. There is a potential flaw in mysql_real_escape_string() (which also applies to the default use of pdo), but this is so esoteric you pretty much have to try to make your code open to an attack based on it.
The bigger issue is that your user input could possibly be used on different databases with different character sets. Hence you should specify the link to the database that the escaped string will be used in. If you do not specify this the the details of the last link opened will be used. If no link has already been used then it will try and connect itself with some default connection parameters and the results are likely to be unpredictable.
If you just escape all the $_POST / $_GET / $_REQUEST arrays (and remember that $_COOKIES array is also subject to being changed by a mischievous user) then the likely place you would do this would be when the scripts are first loaded, when you are unlikely to have connected to the appropriate database.
A further issue is that some of the code you are dealing with (and which you seem not to have the time deal with in detail) is bound to already escape the input data. Hence you will land up double escaping it with strange results. Related (but less likely to be an issue) is escaping numeric fields
I am a tyro in web security and have been researching on it for two days. According to OWSAP, SQL Injection and XSS attacks are the most common over the internet and at the minimal must be handled by every programmer.
So whatever I understood to protect them is the following (you are requested to correct it or add if I am wrong):
Use PDO and prepared statements to prevent SQL Injection
PDO and prepared statements are sufficient to prevent (first-order) SQL Injection and we do not need to do any escaping on input data as the driver handles that.
BUT this may lead you prone to second order SQL injection (see this for more) where a data like ' OR '1'=' may get stored into the database after passing through the PDO and prepared statements as they store raw data and to prevent this makes me feel to rather escape the string first and hence
use $pdo->quote($string) before passing it to prepared statement for storage
But since I also want protection against XSS attack I should use htmlentities() as well (or htmlspecialchars() for minimal case) .I should do this at the output but I may prefer to use at the input side if my output is targeted for HTML only
To summarize,my steps would be
$string ='raw input from user';
$escaped_string=$pdo->quote(htmlentities($string));
$pdo->execute('query to store $escaped_string into the database');
while ouputting
simply echo the stored field from the database.
I want to know whether my approach is secure or not?
If your code is open to second-order attacks, you're not using prepared queries correctly, and do not fundamentally understand what you are doing.
The point of escaping data in a query is to disambiguate the data from the command. The point of using parameters in queries is to fundamentally separate the data from the command. Both of these have absolutely nothing to do with how data is stored in the database.
Every query you do should use parameters for arbitrary data being used within them. If you do not do this, you might as well have no protection at all and will undoubtedly have errors in your application. Always use parameterized queries (and actually use those parameters) for arbitrary data, even if it came from your own database. Who cares where it came from... if you cannot predict what the data is, you know it isn't usable directly in a query.
On XSS attacks... you can prevent some of these by properly escaping data for use in an HTML context if you are outputting HTML pages. This allows you to use arbitrary strings in the context of HTML where the text is preserved. This escapes the data for HTML, meaning that the text won't be parsed as HTML tags. You should only do this escaping on output... not before, or you mangle your data early and make it unusable for other purposes.
BUT this may lead you prone to second order SQL injection
This may, actually, not. There is no such thing like "second order SQL injection". There is just SQL injection only. To prevent it you have to use parameterized queries. As simple as that.
To summarize, your steps would be
$string ='whatever string';
$pdo->prepare('any query that uses ? placeholder for any data');
$pdo->execute([$string]);
while ouputting make your template to do html escaping for any value by default, or apply any other format if told explicitly - i.e. make it raw for the html formatted texts.
This is standard procedure if you can not avoid getting raw input from user, if at all possible avoid using raw input from user. For example:
Best to use stored procedures for these types of things.
<?php
if(isset($_POST['submit'])) {
if($_GET['sort'] == 'alphad') {
$sort = 'alphad'; //not = $_GET['sort']
//Your query
}
}
?>
I intend to use this for a block of text that will be entered by my users. Of course I'd like to avoid malicious misuse of the site.
From what I have read about MYSQL injections and XSS, I only allow simple text, no HTML tags, no links, nothing special just plain text and some literal links.
Would this suffice?
mysql_real_escape_string(strip_tags($_POST['datablock']));
Short answer: NO.
The long answer is more complicated.
You must be sure to protect your SQL queries against injection bugs. The best way to do this is to never directly inject user data into your queries, but instead use the SQL placeholders of a database driver to do the insertion for you. This is the safest method by far. Your queries will end up looking like this:
INSERT INTO table_name (user_id, comment) VALUES (:user_id, :comment)
Data is then bound to the various placeholders in a way that the driver can encode it correctly. Being disciplined about this avoids nearly all SQL injection problems.
You must also protect your HTML from XSS attacks by not allowing users to insert arbitrary HTML with scripting into your pages. You should always render user input as the HTML entitized equivalent unless you're absolutely sure that this user content is free of <script> type tags or JavaScript snuck into various elements. Note that this is very hard to do correctly since JavaScript is not confined to script tags at all. It can appear as attributes on an HTML element or even in CSS style definitions.
Further, you should never use mysql_query or any related functions in a new application. These methods are dangerous by default and will cause you severe harm if you miss even one variable. Automated SQL injection tools have a terrifying list of features, and all that these tools require is one unescaped variable.
Thankfully mysql_query is deprecated, it produces warnings in PHP 5.5.0, and will be removed entirely in future versions of PHP.
At the very least you should be using PDO for your database access. It supports named placeholders and makes it very easy to audit your database interface code to be sure it's safe. Mistakes will stand out. As a safety measure, it might be best to define your query strings with single quotes like 'INSERT INTO ...' so that if you make the mistake of putting in a variable it won't be interpolated by accident but will end up yielding a harmless SQL error.
Ideally you should be using a PHP framework to build your applications. Most of these have standardized methods for safe database access, HTML escaping and XSS protection. It is not something you can do on your own unless you want to spend a year writing a framework of your own.
Binding your SQL parameters rather than building the SQL string manually is also a good practice (see xkcd on Little Bobby Tables).
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)
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.