I have the following code that adds a record to my MySQL database via PHP:
Contact is just a plain string.
$contact = mysql_real_escape_string(stripslashes($_POST["contact"]), $con);
$sql="INSERT INTO custom_downloads (contact) VALUES ('$contact')";
Is this good enough to prevent any sort of SQL injection attacks? What else can I do to cleanse the data?
Yes, mysql_real_escape_string will correctly escape the string so this is safe from SQL injection.
bluebit, your code is secure with regard that you're protecting against SQL Injection but you're not secure against things like XSS (Cross Site Scripting). This is the ability to pass Javascript into this field and then when you output it, you're outputting the Javascript.
To avoid this you can run your input through strip_tags() www.php.net/strip_tags this will remove all HTML tags from your input, thus getting rid of
Here is a nice function that you can reuse for all inputs you're receiveing from $_POST and wish to secure
$cleanInput = cleanPost($_POST['contact']);
function cleanPost($item) {
return mysql_real_escape_string(strip_tags(stripslashes($item)));
}
There is also a built-in function in PHP for handling input types called filter_var() This allows you to specify wether you want to remove HTML and such, just like strip_tags()
Hopet this you realise you need to protect against SQL Injection and XSS.
You can never be sure that contact will be a plain string -- it comes from "out there", which automatically makes it unsafe. You should never trust unsafe input, thus parameterized query is the only way to go.
See this article. Granted, it covers an uncommon situation, but it's better to be safe than sorry.
It will not protect you from javascript ; if this string is javascript, and you later display it on a web page, it could be executed.
To be protected from that, you could use htmlentities.
Related
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'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)
I need to check something here, I know with some code they filter out AS the input is obtained in the one single line of code, here I have done it AFTER obtaining the code, in a sequential order, is this also acceptable? or do I have to figure out someway of filtering and escaping the data in the one line whilst at the same time obtaining the data? Here's a sample of what Im sort of talking about...
// Get data and prevent XSS attack
$user = htmlentities($_POST['email'], ENT_QUOTES, 'UTF-8');
$pass = htmlentities($_POST['pass'], ENT_QUOTES, 'UTF-8');
// MySQL Injection prevention
$userdata = mysql_real_escape_string($user);
$passdata = mysql_real_escape_string($pass);
Thoughts?
Key objective I'm trying to achieve here is to escape a MySQL injection attempt AND prevent an XSS attack
Key objective I'm trying to achieve here is to escape a MySQL injection attempt AND prevent an XSS attack
You can't do both of those at the same time.
SQL-escaping needs to happen at the point you create SQL queries including text strings. Although you are better off using parameterised queries (eg mysqli or PDO), in order not to have to worry about it.
HTML-escaping needs to happen at the point you create HTML markup including text strings. Although in an ideal world you'd be using a templating language that HTML-escaped by default, so you didn't have to worry about it.
If you apply both HTML-escaping and SQL-escaping at the input stage instead of their respective output stages, you'll get HTML-encoded data in your database that you won't be able to apply consistent text handling to (search, substrings, etc), and you'll get SQL-encoded data spat out onto the page where the value hasn't gone through a database I/O cycle (the cause of the O\\\\\\\\'Reilly problem. Plus you will still be at risk from any data that hasn't gone through the input path - for example fetch a string from the database, process it and return it to the database, and it'll not have had an escaping step and you're vulnerable to SQL injection again.
Neither escaping scheme is suitable to blanket-apply to input. Input filtering should only be about blocking characters you never want to handle and enforcing business rules. Do output escaping only at the moment you move text content into a new context - and wherever possible use frameworks that prevent you from having to manually escape at this point.
It is not enough to use mysql_real_escape_string. There are certain situations where invalid multi-byte encodings can be exploited to inject SQL attacks (unlike with addslashes, this type of attack with mysql_real_escape_string can only happen if the character encoding is overridden in the connection string).
You should also use prepared statements when interacting with MySQL.
With regard to XSS, consider integrating HTML Purifier.
HTML Purifier is a standards-compliant HTML filter library written in PHP. HTML Purifier will not only remove all malicious code (better known as XSS) with a thoroughly audited, secure yet permissive whitelist, it will also make sure your documents are standards compliant, something only achievable with a comprehensive knowledge of W3C's specifications.
I will prefer using a function to pass all my string.
function safe($value){
return mysql_real_escape_string($value);
}
If i want to collect input i will do this:
$name=safe($_POST['name']);
In PHP, I know that using parameterized queries is the best way to prevent SQL injection.
But what about sanitizing user input that will be used for other purposes, such as:
Displaying back to a user (potential cross-site scripting vector)
Addressing an email or filling in the message body
Is htmlentities() the best way to sanitize for non-database usage? What is considered to be best practice here?
In php the best xss filter is:
htmlspecialchars($_POST['param'],ENT_QUOTES);
The reason why you also have to encode quotes is becuase you don't need <> to exploit some xss. for instance this is vulnerable to xss:
print('link');
You don't need <> to execute javascript in this case because you can use
onmouseover, here is an example attack:
$_REQUEST[xss]='" onMouseOver="alert(/xss/)"';
the ENT_QUOTES takes care of the double quotes.
E-mail is a bit different, javascript shouldn't be executed by the mail client, and if it is then your site isn't affected due to the Same Origin Policy. But to be on the safe side I would still use htmlspecialchars($var,ENT_QUOTES);. HOWEVER, PHP's mail() function can succumb to a different type of vulnerability, its called CRLF injection. Here is an example vulnerability against PHP-Nuke. If you have a function call like this: mail($fmail, $subject, $message, $header); Then you must make sure that a user cannot inject \r\n into $header.
Vulnerable code:
$header="From: \"$_GET[name]\" <$ymail>\nX-Mailer: PHP";
patched:
$_GET[name]=str_replace(array("\r","\n"),$_GET[name]);
$header="From: \"$_GET[name]\" <$ymail>\nX-Mailer: PHP";
You may also want to checkout HTML Purifier which will strip any dangerous HTML and leave on safe input. You can also create your own rules on what HTML to allow/disallow.
http://htmlpurifier.org/
Well you can first create rules for certain fields, like email the only thing it should consist of is letters, numbers, # (at-symbol? what is it really called), and a period, so you cannot form an XSS out of that so no need to waste resources using htmlentities() or htmlspeicalchars().
No,
1) prepared statements are not a solution to SQL injection. In most cases prepared statements implies variable binding and therefore transparent escaping which is an effective way to prevent SQL injection.
2) you DO NOT sanitize input - you sanitize output. By all means validate input (e.g. make sure start date comes before end date), but the repsentation of data should only be changed at the point where it leaves your PHP code. The method for sanitizing data written directly into HTML is different from how you would sanitize data written into a URL is different from how you sanitize data to write it into a javascript string variable is different from how you sanitize data for insertion into an SQL statement is different from how you sanitize data before you send it to modem is...
...what are you going to do? create every possible representation of the data? Create a universal represenation of the data?
http://xkcd.com/327/
C.
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.