Understanding input escaping in PHP - php

One thing that's always confused me is input escaping and whether or not you're protected from attacks like SQL injection.
Say I have a form which sends data using HTTP POST to a PHP file. I type the following in an input field and submit the form:
"Hello", said Jimmy O'Toole.
If you print/echo the input on the PHP page that receives this POST data, it comes out as:
\"Hello\", said Jimmy O\'Toole.
This is the point where it gets confusing. If I put this input string into (My)SQL and execute it, it'll go into the database fine (since quotes are escaped), but would that stop SQL injection?
If I take the input string and call something like mysqli real_escape_string on it, it comes out like this:
\\"Hello\\", said Jimmy O\\'Toole.
So when it goes into the database via (My)SQL, it ends up as:
\"Hello\", said Jimmy O\'Toole.
This obviously has too many slashes.
So if the input comes through HTTP POST as escaped, do you have to escape it again to make it safe for (My)SQL? Or am I just not seeing something obvious here?
Thanks in advance for any help.

Ah, the wonders of magic quotes. It is making those unnecessary escapes from your POST forms. You should disable (or neutralize) them, and many of your headaches go away.
Here's an exemplary article of the subject: http://www.sitepoint.com/blogs/2005/03/02/magic-quotes-headaches/
Recap: disable magic quotes, use real_escape_string().

Instead of relying on escaping I would use parametrized SQL queries and let the mysql driver do whatever escaping it needs.

It looks like your PHP server has the Magic Quotes feature enabled - that's where your first set of slashes comes from. In theory, it should then be unnecessary to call the escape functions - but when the app runs on a server with magic quotes disabled, you're suddenly wide open to SQL injection while thinking you aren't.
As chakrit wrote, escaping is not the best way to protect yourself - It's much safer to user parameterized queries.

What's going on is that you have Magic Quotes turned on in your PHP configuration.
It's highly recommended that youturn magic quotes off - in fact, they've been removed from PHP 6 completely.
Once you disable magic quotes, you'll see the POSTed text coming back exactly as you typed it in to the form: "Hello", said Jimmy O'Toole.
It's now obvious that you need to use the mysql escaping functions or even better, prepared statements (with prepared statements you can't forget to escape a string as it's done for you).

Obvious is the keyword for a hacker.
I think escaping normally should be enough, but protecting against just the quotes might not be enough.
See this SQL Injection cheatsheet, it's a good list of test you can run and see if too many slahses is a good thing or not.
And don't forget to escape other kinds of values too, i.e. numeric fields and datetime fields can all be injected just as easily as strings.

Related

Sanitizing both HTML and SQL at once?

Right now I am using htmlspecialchars(mysql_escape_string($value)), but is there a way to sanitize it with one statement rather than a nested statement?
Well there's no one function that handles both of them.
You can use prepared statements and html puffier class, maybe then the "look and feel" will be little bit better :)
mysql_real_escape_string has actually fallen out of favor lately.
It is now preferred to use PDO or mysqli. They both come with PHP by default. They use something called parameterized queries to access the database, rather than having you write the SQL command yourself. This means that you don't need to worry about escaping anymore, since the query and the variables are passed into the function separately.
You can learn more about PDO here:
http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
On a related note, it is conventional to store user-supplied input into the database "as it was written", rather than using htmlspecialchars. You should then use htmlspecialchars to escape the data wherever the it appears on the site. This is a convention recommended by OWASP.
This is because you need to escape different things depending on context. This string:
' <script src="http://example.org/malice.js"></script> ]}\\\\--
...will need to be treated differently if it is used as a parameter in JSON (the quotes and backslashes and ] and } need to be escaped), HTML (the quotes and <s need to be escaped), or written as a URL (almost everything needs to be escaped). If you need to spend time instructing your JavaScript to un-encode the HTML, then your code is going to be confusing quickly.
This approach also makes fixing bugs simpler: if your site has a bug where content isn't escaped properly on a single page, then you can update the page and everything is fixed. If your site has a bug where the data is getting stored in the database incorrectly, then you need to fix everything in the database (which will take much longer and harm more users).

Stripslashes doesn't work for my magic-quotes in PHP

I have started using magic quotes and I have encountered a small problem, an easy problem I guess which I can't figure out.
I wan't to use striplashes which it does not remove when I write something in my textarea
Code:
<?php
echo "Removed Slashes: ";
// Remove those slashes
if(get_magic_quotes_gpc())
echo stripslashes($_POST['question']);
else
echo $_POST['question'];
?>
<form method='post'>
Question: <input type='text' name='question'/><br />
<input type='submit'>
</form>
I also tried this one which actually works!:
<?php
$str = "Is your name O\'reilly?";
// Outputs: Is your name O'reilly?
echo stripslashes($str);
?>
But now I want to use my input for the website for secutiry reasons
I cant put it any better than this comment by cHao on the manual page
The very reason magic quotes are deprecated is that a one-size-fits-all approach to escaping/quoting is wrongheaded and downright dangerous. Different types of content have different special chars and different ways of escaping them, and what works in one tends to have side effects elsewhere. Any sample code, here or anywhere else, that pretends to work like magic quotes --or does a similar conversion for HTML, SQL, or anything else for that matter -- is similarly wrongheaded and similarly dangerous.
Magic quotes are not for security. They never have been. It's a convenience thing -- they exist so a PHP noob can fumble along and eventually write some mysql queries that kinda work, without having to learn about escaping/quoting data properly. They prevent a few accidental syntax errors, as is their job. But they won't stop a malicious and semi-knowledgeable attacker from trashing the PHP noob's database. And that poor noob may never even know how or why his database is now gone, because magic quotes (or his spiffy "i'm gonna escape everything" function) gave him a false sense of security. He never had to learn how to really handle untrusted input.
Data should be escaped where you need it escaped, and for the domain in which it will be used. (mysql_real_escape_string -- NOT addslashes! -- for MySQL (and that's only unless you have a clue and use prepared statements), htmlentities or htmlspecialchars for HTML, etc.) Anything else is doomed to failure.
Really, take the advice. Don't use them, you won't learn anything useful by trying them out, just forget they ever existed.
Take a look at this article http://www.sitepoint.com/magic-quotes-headaches and this one http://econsultancy.com/us/blog/2663-web-app-security-basics-filtering-input-and-escaping-output for more information.
Well it's easy to attack but seemingly more effort to help. So here's my attempt at being helpful.
So, you are posting data back to the server and you want to ensure that whatever the user posts back does not end up somewhere that it can act maliciously.
The naive strategy you have adopted it to say ok, I'll sanitise data generically by turning on the magic quoting, which should escape all of the nasties...
However, it doesn't. Your job is to ensure that you use a custom sanitisation strategy when dealing with untrusted data, depending completely on how you use it. A good resource for learning where you should allow untrusted data to enter a particular location, and how to escape untrusted data can be found at OWASP
You'll notice that not all locations are suitable for untrusted data, escaped or otherwise. This highlights the fact that to truly implement secure websites you have to consider both where untrusted data is going and how data is getting there.
This question is more directly focussing on the how, because we are considering (and attacking the use of) a generic escaping mechanism. You are implying that turning on magic quotes is a suitable method for escaping data destined to all locations your untrusted data can end up.
Best practice says that actually, you need to use an escaping mechanism that is suitable for the location(s) you intend to use it. As has already been pointed out, the use of mysql_real_escape_string is a popular function which is specific to escaping strings for use in a MySQL query. People do use this mechanism, but the need to manually escape your data with this mechanism is superceded by the correct use of PHP Data Objects (PDO). (Binding your untrusted data to a parameter rather than manually building up query strings).
Other obvious escaping mechanisms include encoding html characters using htmlspecialchars or htmlentities and, the more generic quote escaping mechanisms addslashes and addcslashes. There are even escaping methods for command line arguments escapeshellarg and escapeshellcmd
So you can see that escaping data properly is far less trivial than applying magic quotes to all of your incoming data, and there are often well established mechanisms for escaping data safely depending on the location you intend to use it.
Easy fix to your problem is to create a simple function that you push all your data through if it is going to be touching your DB. Can be modeled as such:
function sanitizeString($var)
{
$var = strip_tags($var);
$var = htmlentities($var);
$var = stripslashes($var);
return mysql_real_escape_string($var);
}//end sanitizeString

PHP Delimiting Quotation marks

I'm working on a PHP comment system and came across the problem that the commentator's quotation marks are delimited when written to the comment file, so the output would end up like this for example:
"That is your father\'s! It\'s special to him!" (random sentence). How do I disable this?
The backslashes are added to the database query to prevent SQL injection. You can use the stripslashes() function to remove them when you retrieve the comments from the database.
You should also take a look at magic quotes.
It depends on version of PHP and it's configuration. Older versions (older than 5.3) had this enabled by default. It adds the quotes when you post your comment (so it will be stored in the database with the quotes). You can disable this behavior:
http://cz.php.net/manual/en/function.get-magic-quotes-gpc.php
http://cz.php.net/manual/en/function.set-magic-quotes-runtime.php
http://cz.php.net/manual/en/info.configuration.php#ini.magic-quotes-gpc
For existing comments, you'll have to run some cleanup script that will fetch all rows, performs stripslashes() on it and save it back.
Escaping your queries should be done by mysql_real_escape() anyway, relying on magic quotes is suicide, so if you think about it, it's safer to turn them off completely and escape the queries manually.
Turn gpc_magic_quote 's off in your php.ini .
Those backslashes are there to escape the quotation marks from the SQL engine.
That style of programming is quite common with the mysql_* series of functions which take a string directly from the program and execute it directly in the database engine. This is notoriously prone to SQL injection attacks and, as you've discovered, corrupting your data. (When applied consistently, you can always de-corrupt the data on the way back to the user, with the stripslashes() function, but that also must be done consistently.)
The far better approach in my humble opinion is to use prepared statements and let the database libraries insert data directly into the database without any escaping or un-escaping involved. This also completely removes the risk of SQL injection attacks. (Though you're still free to write insecure code.)

How to secure $_REQUEST?

How can I secure $_REQUEST before inserting to mysql database? For example following:
$message = $message = $_REQUEST['message'];
$tags = $_REQUEST['item']['tags'];
Thanks.
Depends on what you mean by "secure", and how you intend to insert the data. $_REQUEST isn't broken or anything; it's just that the data in it can be just about anything, so you'll need to "sanitize" it before you use it.
For example, if 'some_id' should only ever be an int,
$some_id = intval($_REQUEST['some_id']);
will ensure that $some_id is always an int. (Even if it didn't exist in $_REQUEST! In which case it will be 0.)
If you use prepared statements, a lot of the issues with $_REQUEST data go away -- that is, extensions like PDO and mysqli will escape parameters for you (if you use placeholders, like all good prepared statements should!), so all you have to do is make sure the data is valid. (For example, above, it'd have been a good idea to make sure $_REQUEST['some_id'] was set first -- since we didn't, we got a 0 back, which may not be valid.)
If you don't use prepared statements, then you have a little more work ahead of you. You'll need to use mysql_real_escape_string to escape strings as you feed them into the database, like so:
$some_string_sql = mysql_real_escape_string($_REQUEST['some_string']);
$id = intval($_REQUEST['id']);
mysql_query("UPDATE stuff SET some_string = '$some_string_sql' WHERE id = $id");
Note that i did this just for the query! Too many PHP noobs think they can just apply some magic formula to everything in $_REQUEST at the beginning of their script to make everything safe. You kinda can, if you're always just feeding it directly into an SQL query -- but it trashes your data if you're using it for other stuff! For example, if you write the data to a file as well, blindly escaping the data will leave you with a bunch of ugly backslashes in your file. You should never have to *un*escape your data -- it should always be escaped as you need it, for the specific purpose you intend to use it. (htmlentities for arbitrary data being printed to the screen, mysql_real_escape_string for stuff going into an SQL query.)
Also note: If you have magic_quotes_gpc enabled on your site, disable it for the reasons mentioned in the previous paragraph. Properly escaped stuff will break in the presence of magic quotes, because it's already been "escaped" once (half-assedly, hence the quotes) by PHP! Fortunately this misfeature will be removed from PHP 6, if it ever ships. But til then, if you have magic quotes enabled, you'll need to stripslashes(anything from $_REQUEST, $_GET, $_POST, or $_COOKIE) before you can properly escape it. DO NOT rely on the magic quotes -- they're a convenience thing, and not at all designed for security.
You should just not forget escaping your data when injecting them in some SQL queries.
Either use a function to escape the data :
Depending on the API you're working with :
mysql_real_escape_string,
mysqli_real_escape_string,
or PDO::quote
Or you could use Prepared Statements :
Those might seem a bit harder to understand, at first -- but they are worth investing sometime...
With mysqli,
And with PDO.
Then, of course, when using the data from the database to generate some output, the same idea applies : escape the output.
If you are generating some HTML output, you'll typically want to use something like htmlspecialchars.
Or, to allow some specific HTML tags, see HTML Purifier.
If you are generating some other kind of output, you'll have to find how to escape your data specifically for this type of output.
Use either mysql_real_escape_string() or PDO's prepared statements. I recommend the latter, as it also helps keep your queries nice and tidy.
As secure as anything could be in them.
The user can change those values to whatever they want.
So, not secure at all. Always sanitize your inputs.
There is nothing to secure.
Your database input should be just properly formatted.
For the strings it's quoting and escaping.
As long as your input data is limited to strings and you follow formatting rules, no special security required.

Do PHP PDO prepared statements need to be escaped?

On the PDO::Prepare page it states,
"and helps to prevent SQL injection attacks by eliminating the need to manually quote the parameters"
Knowing this, is there a PHP function like mysql_real_escape_string() that takes care of escaping stings for PDO? Or does PDO take care of all escaping for me?
EDIT
I realize now that I asked the wrong question. My question really was, "What all does PDO take care of for me?" Which I realize now with these answers that it really only removes the need to escape the quotes. But I would still need to do any other PHP sanitize calls on the values that I pass to the execute function. Such as htmlentities(), strip_tags()...etc...
PDO does not escape the variables. The variables and the SQL command are transferred independently over the MySQL connection. And the SQL tokenizer (parser) never looks at the values. Values are just copied verbatim into the database storage without the possibility of ever causing any harm. That's why there is no need to marshall the data with prepared statements.
Note that this is mostly a speed advantage. With mysql_real_escape_string() you first marshall your variables in PHP, then send an inefficient SQL command to the server, which has to costly segregate the actual SQL command from the values again. That's why it's often said that the security advantage is only implicit, not the primary reason for using PDO.
If you concat the SQL command and don't actually use prepared statments (not good!), then yes, there still is an escape function for PDO: $pdo->quote($string)
Very few people here understand what escaping is and when to use it.
Escaping itself does not make any data "safe". It just escapes delimiters, to distinguish a delimiter from a part of data. field = 'it's me' will cause an error, while field = 'it\'s me' will not. That's the only purpose of escaping. So, it works only when you use quotes. If you don't - escaping becomes useless.
Do you use quotes with placeholders? No. Thus, no escaping would be sensible.
When you are binding your variables, it works a very different way: it does not send the whole query to the server, but sends your prepared query separated from the bound data. So it cannot interfere. And thus makes no injection possible.
Yes and no:
Literals which you embed into the statement string need to be escaped as normal.
Values which you bind to the prepared statement are handled by the library.
If you prepare a statement and use bindParam or bindValue to supply variables, you do not need to escape the variables. Note that these functions assume that the variable contains a string, so use the third parameter to bindValue if you want to use booleans or floats.
You don't have to worry about it. PDO does not require you to escape your data before passing it along to the database.
Edit: Just to be clear, I mean to say that as long as you are passing variables into your parameters (for example, the value of a form field), you don't have to worry about it. However, if you're passing variables that you've defined as strings, for example, then obviously you need to escape anything that needs escaping in that string in order to avoid breaking syntax. However, this wouldn't even make much sense since one of the main advantages of PDO is that you're passing information from the user to the database without having to sanitize it yourself, and there aren't many times (if any?) that you would be passing strings that you yourself had defined.
Also, make sure you still sanitize your data for type. For example, make sure it's an integer if you expect it to be, make sure it's less than or greater than x if you expect it to be, etc.

Categories