I am working on a portal and I have these few questions regarding saving data in MySQL tables :
Should I save varchar field escaped ?
i'm using now mysql_real_escape_string() for avoiding string-injection.
Why should I save them unescaped (this was proposed by a guy on this website) and how would that work for characters like single and double-quotes. Doesn't it wreck the SQL command ?
easy talking around this topic.
And one last thing....I was using addslashes and stripslashes before using mysql_real_escape_string and it worked for me (of course, with mysql-injection of malicious code chance, which I recently discovered and documented myself on it)...
thanks
The very basic thing any programmer must learn is the meaning of context.
What am I going about here? If you knew the meaning of context, you wouldn't have asked this question. Now that (I hope) you know, you won't ask how to show <test> as HTML, or how to pass a variable to javascript.
So what's it all about? It's really easy. Context is the simple fact that something in a system may mean something entirely different somewhere else.
For example, in your case, a PHP string may mean something entirely different to MySQL. You can't just pass the string and expect everything to run smoothly - it won't.
So, now that you know what context means, you need to know something else that is important. You always need to convert a value from the older context to the newer one. Always.
Again, in your case, it's mysql_real_escape_string(), but a word of warning; conversion functions are context specific, so, for example, you can't use mysql_real_escape_string() to pass a string from PHP to Javascript. Similarly, you can't just use addslashes() and expect it to work. In fact, I'd argue that addslashes() is a completely useless and misleading function. Do NOT use it unless you are very sure of what you are doing.
Should I save varchar field escaped ?
No. You should escape data so that characters (in the data) with special meaning in SQL won't cause you problems.
Once it passes through SQL and gets stored in the database, it won't be escaped any longer.
i'm using now mysql_real_escape_string() for avoiding string-injection.
Don't do that, instead use prepared statements and parameterized queries
I was using addslashes and stripslashes
addslashes is a basic form of escaping. It is pointless unless you know exactly what the target of the data is. You should use something more specific where such a thing exists (and you are – mysql_real_escape_string)
stripslashes does the opposite of addslashes. Using them together is utterly pointless.
Related
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).
There is a (ugly)project I was asked to help with by doing a specific task.
The thing is, I don't have any control over the other files in the site much less over the server configuration. Some data I'm going to use comes from a query like this:
'SELECT * FROM table where value like "'.$unsafe.'"';
$unsafe is an unescaped value coming from $_POST or $_GET.
I checked the server, is PHP5.1.6 and has magic_quotes_gpc On so the data is being auto escaped.
Is this query breakable? Being $unsafe between colons gives me the impression It cant be broken but maybe I'm missing something.
I know magic_quotes_gpc is deprecated because of its insecurity so I'm concerned about it, not because of the application security which fails every where but for my own knowledge.
EDIT: I'm aware of the security implications of *magic_quotes_gpc* and I never use it in my own projects. I always use parameterized queries to avoid injection but this time I was asked to add a very specific pice of code in a friend/client project, so I cant change what is already done. I'd like to know if there is a specific value I can use to create an injection so I can illustrate my friend why he should change it.
if the DB is mysql use mysqli_real_escape_string() instead, if the PHP version is very old you can use the mysql_real_escape_string (not recommended at the moment).
even if the variable is between colons it can be injected, you just need to close the colons inside the value of the variable and then inject whatever you want afterwards.
With regard to your edit: You asked "I'd like to know if there is a specific value I can use to create an injection so I can illustrate my friend why he should change it."
According to the manual page for mysqli_real_escape_string(), the characters it escapes are as follows:
NUL (ASCII 0), \n, \r, \, ', ", and Control-Z.
The old mysql_real_escape_string() function also escapes the same characters.
This gives you a starting point as to which characters can be used to do injection attacks in MySQL. Magic quotes only escapes the quote characters and the slash character, which clearly leaves several gaping holes that can be exploited.
In an easy world, the above information would be enough for us to fix the escaping by doing a string replace on the remaining unescaped characters.
However, both the real_escape functions also require an active database connection for them to work, and this leads us to a further complication: character sets.
Further attacks are possible if the database has a different character set to PHP, particularly with variable-length character sets such as UTF-8 or UTF-16.
An attacker who knows (or can guess) the character set that PHP and the DB are using can send a crafted injection attack string that contains characters that PHP would not see as needing escaping, but which would still cause succeed in hacking MySQL. This is why the real_escape functions need to access the DB in order to know how to do the escaping.
Further resources:
Php & Sql Injection - UTF8 POC
SQL injection that gets around mysql_real_escape_string()
I hope that gives you a few pointers.
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
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.
Recently, I had an audit run on some of my sites by a client. One of the things they came back with was that I could be sanitizing the input data a little better as people could still cause potential harm to the database.
The function below is what I am currently using (a leftover from the old developer) but I cannot see where the potential issue may lie.
The string that gets passed through to the database will be displayed via XML which in turn is read by a Flash application.
Could anyone tell me what I might be missing? Thanks
function secure_string($string)
{
return (strip_tags(addslashes(mysql_real_escape_string(
stripslashes($string)))));
}
Better use the new PHP function filter_var() for cleaning input. New and better.
It looks like there's too much going on in that function. mysql_real_escape_string() already escapes everything you need to escape, so there's no need to run addslashes() on that. In fact, it could do more harm than good by escaping the backslashes mysql_real_escape_string() creates.
mysql_real_escape_string is the last step, you shouldn't use it your application logic. It's sole purpose is to pass strings to the database, so use it only when constructing queries. You can pass anything to mysql_real_escape_string and it will make sure you can safely store it in the database.
For the rest, it depends what do you want. If you want to strip tags, use strip_tags, etc.
Depends on where the "secured" string will be used. If it's going to be used in the database, you only need mysql_real_escape_string(), nothing more. If it's going to be displayed in html, you only need htmlentities(), nothing more. In short: your code is doing way too much, which could even be harmful.
If you want to store it in the database for displaying it in html lateron (like a comment, for example), you should be using mysql_real_escape_string() when storing the string and htmlentities() when displaying it.
If your server uses php 5.2 or better, you should use filter_var for the XML part.
$output = filter_var($input, FILTER_SANITIZE_STRING);
To store something into your database, use PDO and parameterized queries.
It's a misnomer to try and fix the problem at input time, since the problem happens at output time. See my answer over here:
What’s the best method for sanitizing user input with PHP?