This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
The ultimate clean/secure function
After reading up on PHP security I have the feeling that anything I code is always insecure. So to combat the security issues of user input I have created a function that allows me to escape and strip user input for any usage situation.
I would just like to know if this is in fact secure and if I could make it more secure. Also what kind of attacks would this prevent? From what I can tell XSS by using _GET, HTML input and MYSQL injection would have been prevented?
function _INPUT($name,$tag,$sql,$url)
{
if ($_SERVER['REQUEST_METHOD'] == 'GET')
$filter = ($_GET[$name]);//Assign GET to filter variable
if ($tag == true)//Remove all HTML, PHP and JAVASCRIPT tags
{
$filter = strip_tags($filter);
}
if ($sql == true)//If MYSQL escaping is enabled
{
$filter = mysql_real_escape_string($filter);
}
if ($url == true)//If URL encoding is enabled
{
$filter = urlencode($filter);
}
return $filter;
}
$output = _INPUT('name',true,true,true);
I will be using prepared statements for MYSQL too, although I need to read up on them more to fully understand how it prevents injection.
Thank you for your time.
Once again, there is no universal escape function that just magically makes things "secure".
See this: https://stackoverflow.com/a/7810880/362536
Different escape methods are used for different things. You can't just run a bunch of data through a bunch of functions that are supposed to be used in specific contexts. You are creating garbage data, and are no more secure than you were with the raw user data in the first place.
No,
For SQL Injection prevention, you really want to be using prepared statements. This is a safer way to do this, instead of escaping quotes. You also want to use htmlspecialchars() for escaping HTML tags, instead of just stripping them away, but that's up to you.
This is kind of an eternal question, and the answers vary across wanted usage: for prepared queries, I believe it’s 100 % safe to use its own variables system and let it handle the input. For HTML output, stripping tags may not always be what you want; moreover, it’s kind of safer to do a whitelist of what to allow in input than blacklist, because you know, hackers have fantasy. For URL output, your solution should be fine, but be aware that some other platforms may do a little different URL-encoding (see the difference between a string URL-encoded by Java standard libraries and iOS/Mac libraries, i.e.).
Related
As always I start this saying that I am learning.
I saw in several books and even here, that a lot of user when we are talking about sanitize, for example, Form>Input>Submit, they use
function sanitizeexample($param)
{
$param = stripslashes($param);
$param = strip_tags($param);
$param = htmlentities($param);
return $param;
}
$name = sanitizeexample($_POST['name']);
Instead of JUST:
function sanitizeexample($param)
{
$param = htmlentities($param);
return $param;
}
$name = sanitizeexample($_POST['name']);
So here the question. Do stripslashes() and strip_tags() provide something else regarding to security? Or it´s enough with htmlentities().
And I´m asking JUST to know which is the best to use.
Whether strip_tags() provides a value-add is dependent on your particular use case. If you htmlentities() a string that contains html tags, you're going to get the raw html content escaped and rendered on the page. The example you give is probably making the assumption that this is not what you want, and so by doing strip_tags() first, html tags are removed.
stripslashes is the inverse to addslashes. In modern (PHP >= 5.4) PHP code, this is not necessary. On legacy systems, with magic_quotes_gpc enabled, user input from request variables are automagically escaped with addslashes so as to make them "safe" for direct use in database queries. This has widely been considered a Bad Idea (because it's not actually safe, for many reasons) and magic_quotes has been removed. Accordingly, you would now not normally need to stripslashes() user input. (Whether you actually need to is going to be dependent on PHP version and ini settings.)
(Note that you would still need to properly escape any content going into your database, but that is better done with parameterized queries or database-specific escaping functions, both of which are outside the scope of this question.)
It depends on your goals:
if you're getting user's data passed from html form - you should
definitely apply strip_tags(trim($_POST['name'])) approach to
sanitize possible insecure and excessive data.
if you are receiving uploaded user's file content and need to save
content formatting - you have to consider how to safely process and
store such files making some specific(selective) sanitizing
Currently I use this strategy:
After submitting a HTML form or data sent using jQuery's $.get() or $.post() I need to know what is come and then apply logic on the basis of that.
suppose, I've got $_POST['username'], $_POST['password'] and $_POST['login_submit_button'].
In my processing script file, I do like this:
if(isset($_POST['login_submit_button']) && isset($_POST['username']) && $_POST['username'] != "" && isset($_POST['password']) && $_POST['password'] != "") {
// calling a common function safe_vars() which does
// mysql_real_escape_string(stripslashes(trim($any_variable_need_to_become_safe)))
// and now using the above variables for different purposes like
// calculation, insertion/updating old values in database etc.
}
I know all this logic is wrong or having serious issues, so I want a much-secure and perfect solution instead of this. I welcome to find out vulnerabilities and severe security-bleaches in my strategy. This question can help others too, if answers came more explanatory, this can be informative community wiki.
There is no way to make a generic super "make things safe" function.
mysql_real_escape_string
You shouldn't use this at all. It uses the old mysql API, and assumes you are going to be manually smashing strings together to make SQL. Don't do that. Use PDO or mysqli and a function that deals in prepared queries and bound arguments.
stripslashes
This is an antidote to magic quotes. If magic quotes are not on it will destroy data. Don't use it. Turn magic quotes off instead.
trim
This destroys data. Don't use it unless you really want to remove white space at the start and end of the string.
Escape data for the target language immediately before inserting data into that language.
For SQL, use bound arguments and prepared queries.
For HTML, use htmlspecialchars or a template language that does escaping for you, such as mustache.
Alternatively, (if you want to allow HTML) parse it, generate a DOM, filter it using a whitelist, then serialise it back to HTML.
For JSON, use encode_json
etc.
You only need to stripslashes if you have magic_quotes enabled (use get_magic_quotes_gpc to check)
You should white list filter your POST vars using filter_var or ctype_* or preg_match (as well as checking bound conditions such as length and presence)
Use prepared statements / PDO for your queries to ensure proper escaping
Escape any html output with htmlentities
Nothing is bullet proof, however the above are good practices to avoid SQL injection / XSS.
I am a PHP newbie and am working on a basic form validation script. I understand that input filtering and output escaping are both vital for security reasons. My question is whether or not the code I have written below is adequately secure? A few clarifying notes first.
I understand there is a difference between sanitizing and validating. In the example field below, the field is plain text, so all I need to do is sanitize it.
$clean['myfield'] is the value I would send to a MySQL database. I am using prepared statements for my database interaction.
$html['myfield'] is the value I am sending back to the client so that when s/he submits the form with invalid/incomplete data, the sanitized fields that have data in them will be repopulated so they don't have to type everything in from scratch.
Here is the (slightly cleaned up) code:
$clean = array();
$html = array();
$_POST['fname'] = filter_var($_POST['fname'], FILTER_SANITIZE_STRING);
$clean['fname'] = $_POST['fname'];
$html['fname'] = htmlentities($clean['fname'], ENT_QUOTES, 'UTF-8');
if ($_POST['fname'] == "") {
$formerrors .= 'Please enter a valid first name.<br/><br/>';
}
else {
$formerrors .= 'Name is valid!<br/><br/>';
}
Thanks for your help!
~Jared
I understand that input filtering and output escaping are both vital for security reasons.
I'd say rather that output escaping is vital for security and correctness reasons, and input filtering is potentially-useful measure for defence-in-depth and to enforce specific application rules.
The input filtering step and the output escaping step are necessarily separate concerns, and cannot be combined into one step, not least because there are many different types of output escaping, and the right one has to be chosen for each output context (eg HTML-escaping in a page, URL-escaping to make a link, SQL-escaping, and so on).
Unfortunately PHP is traditionally very hazy on these issues and so offers a bunch of mixed-message functions that are likely to mislead you.
In the example field below, the field is plain text, so all I need to do is sanitize it.
Yes. Alas, FILTER_SANITIZE_STRING is not in any way a sane sanitiser. It completely removes some content (strip_tags, which is itself highly non-sensible) whilst HTML-escaping other content. eg quotes turn into ". This is a nonsense.
Instead, for input sanitisation, look at:
checking it's a valid string for the encoding you're using (hopefully UTF-8; see eg this regex for that);
removing control characters, U+0000–U+001F and U+007F–U+009F. Allow the newline through only on deliberate multi-line text fields;
removing the characters that are not suitable for use in markup;
validating the input conforms to application requirements on a field-by-field basis, for data whose content model is more specific than arbitrary text strings. Although your escaping should handle a < character correctly, it's probably a good idea to get rid of it early in fields where it makes no sense to have one.
For the output escaping step I'd generally prefer htmlspecialchars() to htmlentities(), though your correct use of the UTF-8 argument stops the latter function breaking in the way it usually does.
Depending on what you want to secure, the filter you call might be overactive (see comments). Injectionwise you should be safe since you're using Prepared Statements (see this answer)
On a design note you might want to filter first, then check for empty values. Doing that you can shorten your code ;)
I understand that input filtering ... is vital for security reasons.
This is wrong statement.
Although it can be right in some circumstances, in such a generalised form it can do no good but false feeling of safety.
all I need to do is sanitize it.
There is no such thing like "general sanitizing". You have to understand each particular case and it's limitations. For example, for the database you need to use several different sanitization techniques, not one. While for the filenames it is going to be completely different one.
I am using prepared statements for my database interaction.
Thus, you should not touch the data at all. Just leave it as is.
Here is the (slightly cleaned up) code:
It seems there is some overkill in your code.
you are cleaning your HTML data twice while it is possible that you won't need it at all.
and for some reason you are raising an error on success.
I'd make it rather this way
$formerrors = '';
if ($_POST['fname'] == "") {
$formerrors .= 'Please enter a valid first name.<br/><br/>';
}
if (!$formerrors) {
$html = array();
foreach ($_POST as $key => $val) {
$html[$key] = htmlspecialchars($val,ENT_QUOTES);
}
}
I'm quite confused now and would like to know, if you could clear things up for me.
After the lateste Anon/Lulsec attacks, i was questioning my php/mysql security.
So, i thought, how could I protect both, PHP and Mysql.
Question: Could anyone explain me, what's best practice to handle PHP and Mysql when it comes to quotes?
Especially in forms, I would need some kind of htmlspecialchars in order to protect the html, correct?
Can PHP be exploitet at all with a form? Is there any kind of protection needed?
Should I use real_escape_string just before a query? Would it be wrong/bad to use it already within PHP (see sanitize_post function)?
Currently i'm using the following function. The function "sanitizes" all $_POST and $_GET variables. Is this "safe"?
function sanitize_post($array) {
global $db;
if(is_array($array)) {
foreach($array as $key=>$value) {
if(is_array($array[$key])) {
$array[$key] = sanitize_post($array[$key]);
} elseif(is_string($array[$key])) {
$array[$key] = $db->real_escape_string(strtr(stripslashes(trim($array[$key])), array("'" => '', '"' => '')));
}
}
} elseif(is_string($array)) {
$array = $db->real_escape_string(strtr(stripslashes(trim($array)), array("'" => '', '"' => '')));
}
return $array;
}
I'm using PHP 5.3.5 with Mysql 5.1.54.
Thanks.
mysql_real_escape_string deserves your attention.
However direct queries are a quagmire and no longer considered safe practice. You should read up on PDO prepared statements and binding parameters which has a side benefit of quoting, escaping, etc. built-in.
BEST practice is always to use prepared statements. This makes SQL injection impossible. This is done with either PDO or mysqli. Forget about all the mysql_* functions. They are old and obsolete.
Question: Could anyone explain me, what's best practice to handle PHP
and Mysql when it comes to quotes?
That's easy: Use prepared statements, e. g. with PDO::prepare or mysqli_prepare.
There is nothing like "universal sanitization". Let's call it just quoting, because that's what its all about.
When quoting, you always quote text for some particular output, like:
string value for mysql query
like expression for mysql query
html code
json
mysql regular expression
php regular expression
For each case, you need different quoting, because each usage is present within different syntax context. This also implies that the quoting shouldn't be made at the input into PHP, but at the particular output! Which is the reason why features like magic_quotes_gpc are broken (always assure it is switched off!!!).
So, what methods would one use for quoting in these particular cases? (Feel free to correct me, there might be more modern methods, but these are working for me)
mysql_real_escape_string($str)
mysql_real_escape_string(addcslashes($str, "%_"))
htmlspecialchars($str)
json_encode() - only for utf8! I use my function for iso-8859-2
mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}')) - you cannot use preg_quote in this case because backslash would be escaped two times!
preg_quote()
Don't waste the effort using mysql_real_escape_string() or anything like that. Just use prepared statements with PDO and SQL injection is impossible.
I usually use the PHP functions stripslashes and strip_tags on the variables as they come in via $_POST (or $_GET, depending on what you use) and mysql_real_escape_string during the query. (I'm not sure if this is "right" but it's worked for me so far.) You can also use PHP's built in validate filters to check things like email addresses, url's, data types, etc. PDO is supposedly decent at preventing SQL injection but I haven't had any experience with it yet.
The basic workflow should be
$data = $_POST['somefield which will go into the database'];
... do data validation ...
if (everything ok) {
$escaped_data = escape_function($data);
$sql = " ... query here with $escaped_data ... ";
do_query($sql);
}
Basically, data that's been escaped for database insertion should ONLY be used for database insertion. There's no point in pre-processing everything and overwriting all data with db-escaped values, when only 2 or 3 of 50(say) values actually go anywhere near the db.
Ditto for htmlspecialchars. Don't send data through htmlspecialchars unless it's headed for an HTML-type display.
Don't store data in the DB formatted for one particular purpose, because if you ever need the data in a different form for some other purpose, you have to undo the escaping. Always store raw/unformatted data in the db. And note: the escaping done with mysql_real_escape_string() and company does not actually get stored in the db. It's there only to make sure the data gets into the database SAFELY. What's actually stored in the db is the raw unescaped/unquoted data. Once it's in the database, it's "safe".
e.g. consider the escaping functions as handcuffs on a prisoner being transferred. While the prisoner is inside either jail, cuffs are not needed.
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.