I was using php 5.2 earlier. Now I want to upgrade php 5.4. Magic quotes are removed now. I want to make my application work properly. Which function I should use for escaping data mysql_real_escape_string() or addslashes() ?
Which function from the above will give the same results as of magic_quotes_gpc setting??
It's always best to migrate to PDO and prepared statements as outlined by #alex above.
If that isn't feasible, absolutely escape incoming string data with mysql_real_escape_string(), and validate integer data, e.g. using filter_input() as shown in this answer.
addslashes() is not a suitable escaping method for mySQL queries.
Its better to use prepared statements as suggested here for security reasons. Mysql_real_escape_string might not be suffiecient to prevent sql injection e.g. because multibyte character sets can be abused despite the escape function ().mysql_real_escape_string() versus Prepared Statements.
Prepared statements in PHP can be used like this:
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
More information on prepared statements in PHP. So in conclusion, if you have the possibility to change your application to prepared statements, that would be the best way to handle.
UPDATE (totally not recommended)
If you really want to keep the state, use addslashes() for every $GET and $POST variable. It does the same manually what magic_quotes switched on did with all $GET and $POST variables. But i really guess its less work to use mysqli with mysqli_real_escape_string or better, prepared statements :)
http://php.net/manual/de/function.addslashes.php
Because I can not introduce db layer on my application and I want a quick solution, I used addslashes() function because addslashes() escapes single quote ('), double quote ("), backslash () and NUL (the NULL byte) exactly what magic quotes escape.
Code:
foreach (array('_COOKIE','_GET', '_POST') as $_SG) {
foreach ($$_SG as $_SGK => $_SGV) {
$$_SGK = smartQuotes($_SGV);
}
}
function smartQuotes($value)
{
if( is_array($value) ) {
return array_map("smartQuotes", $value);
} else {
if( $value == '' ) {
$value = 'NULL';
} if( !is_numeric($value)) {
$value = addslashes($value);
}
return $value;
}
}
addslashes() gives the same results as of magic_quotes_gpc setting referring from Magic Quotes.
When on, all ' (single-quote), " (double quote), \ (backslash) and NULL characters are escaped with a backslash automatically. This is identical to what addslashes() does.
Use magic_quotes_gpc on PHP 5.4 above
If you still want run magic_quotes_gpc on PHP 5.4 or higher version for your legacy code, you can use yidas/magic-quotes:
https://github.com/yidas/php-magic-quotes
We need to addslashes in Request, Post, Get & cookie. You can achieve it below code. Included below code in your common file .
$la_magicQuotes = array('_REQUEST','_POST', '_GET','_COOKIE');
foreach($la_magicQuotes as $la_superGlobal )
{
if($$la_superGlobal && is_array($$la_superGlobal))
array_walk($$la_superGlobal, 'pr_addslashed_array');
}
function pr_addslashed_array(&$la_val,$lc_key)
{
if (is_array($la_val))
array_walk($la_val,'pr_addslashed_array');
else
$la_val = pr_addslashed($la_val);
}
function pr_addslashed($lc_string)
{
return $lc_string = addslashes($lc_string);
}
Related
function escape($value){
$magic_quotes_active = get_magic_quotes_gpc();
$new_enough_php = function_exists("mysql_real_escape_string");
if ($new_enough_php) {
if ($magic_quotes_active) {
$value = stripslashes($value);
$value = mysql_real_escape_string($value);
}
elseif (!$magic_quotes_active) {
$value = addslashes($value);
}
return $value;
}
}
For a long time I have been using above function for escaping string ? Now, I want to ask that do I need to use that function (I found that over internet for escaping string that works with most versions of PHP) ? OR Its making things unnecesseraily complex ?
No, you should, in fact, avoid using functions like these at all cost! What you should be looking into is the use of prepared statements. Check the doc pages of any of the mysql_* functions, and notice the red warning-thing: the extension has begun the deprecation process, instead PDO or mysqli_* is suggested.
To avoid injection, prepared statements are what you should use... read a couple of articles on the matter, and look into the advantages of both PDO and mysqli_*. That's, I'm afraid the only way forward...
You don't need such functions. Typically it's enough to use addslashes(...). In special cases see the documentation, like #Elias Van Ootegem recommended
I'm using following function to protect my db from injection attacks and etc. for gets.
function filter($data) {
global $db;
$data = trim(htmlentities(strip_tags($data)));
if (get_magic_quotes_gpc())
$data = stripslashes($data);
$data = $db->real_escape_string($data);
return $data;
}
foreach($_GET as $key => $value) {
$data[$key] = filter($value);
}
Question is, i want to filter not only $_GET but $_POST too. How to do that?
And can I reassign value to $_GET or $_POST after filtering? I mean $_GET[$key] = filter($value); instead of $data[$key] = filter($value);..
Don't pre-escape your variables, escape them only at the time you need to escape them.
If you prematurely escape your variable, you'll never know which variable is escaped, and which is not
You'll have to unescape your variables before doing string manipulations, and re-escape them after
Variables coming from different sources (like from an API, from a file or even from your database) won't be escaped. You'll forget to escape them.
You'll have to un-escape all your variables before printing them (you don't want to print the \', I guess)
You can't escape a variable for every possible situation. What about escaping them with escapeshellcmd too ?
PHP did this in the past. It was called magic_quotes_gpc.
But it's so bad practice that it's now deprecated, and it will be removed from the next version of PHP.
It's better to just escape everything at the time you need to. You print a variable ? escape it. You don't have to remember if it's already escaped or not: it's not.
this function makes no sense.
and it doesn't filter anything.
and shouldn't be used this way.
to protect your db from injection attacks you shouldn't do most of the things present in this function and should do many things not present there.
to protect only strings (data chunks enclosed in quotes) from injection attacks you have to use $db->real_escape_string and nothing else.
to protect other query parts you have to use other procedures, as real_escape_string become utterly useless for them
to protect your app from "etc attacks" you have to define what is this "etc" first.
array_walk($_GET,'filter');
array_walk($_POST,'filter');
array_walk($_COOKIE,'filter');
You should probably filter the $key too in case you use it in the query later, but if possible you should use mysql prepared statements and bind variables.
http://www.ultramegatech.com/blog/2009/07/using-mysql-prepared-statements-in-php/
You can change $_GET and $_POST.
I'm no PHP/SQL expert, and I've juste discovered that i had to apply mysql_real_escape_string to secure my SQL INSERTS.
I made a function using several advice found on the net, here it is:
function secure($string)
{
if(is_numeric($string))
{ $string = intval($string); }
elseif (is_array($string))
{
foreach ($string as $key => $value) {
$string[$key] = secure($value);
}
}
else if ($string === null)
{
$string = 'NULL';
}
elseif (is_bool($string))
{
$string = $string ? 1 : 0;
}
else
{
if (get_magic_quotes_gpc()) { $value = stripslashes($string); }
$string = mysql_real_escape_string($string);
$string = addcslashes($string, '%_');
}
return $string;
}
Thing is, when I have a look at my tables content, it contains backslashes.
And then logically, when I retrieve data I have to apply stripslashes to it to remove these backslashes.
Magic Quotes are off.
QUESTION 1)
Now I think that even though I use mysql_real_escape_string to secure my data before SQL insertion, backslashes should not appear in my content ? Can you confirm this ?
QUESTION 2)
If not normal, why are these backslashes appearing in my phpMyAdmin content and retrievals ? What did I did wrong ?
QUESTION 3)
A guess I have is that mysql_real_escape_string could be applied twice, isn't it ?
If so, what could be a function to prevent mysql_real_escape_string being applied many times to a same string, leading to many \\ to a same escapable character ?
Thanks a lot by advance for your inputs guys !
oh, what a senseless function. I know it's not your fault but ones who wrote it in their stupid articles and answers.
Get rid of it and use only mysql_real_escape_string to escape strings.
you have mixed up everything.
first, no magic quotes stuff should be present in the database escaping function.
if you want to get rid of magic quotes, do it centralized, at the very top of ALL your scripts, no matter if they deal with the database or not.
most of checks in this function are useless. is_bool for example. PHP will convert it the same way, no need to write any code for this.
LIKE related escaping is TOTALLY distinct matter, and has nothing to do with safety.
is numeric check is completely useless, as it will help nothing.
Also note that escaping strings has nothing to do with security.
I's just a syntax rule - all strings should be escaped. No matter of it's origin or any other stuff. Just a strict rule: every time you place a string into query, it should be quoted and escaped. (And of course, if you only escape it but not quote, it will help nothing)
And only when we talk of the other parts of query, it comes to the SQL injection issue. To learn complete guide on this matter, refer to my earlier answer: In PHP when submitting strings to the database should I take care of illegal characters using htmlspecialchars() or use a regular expression?
Your stripslashed $string is stored to the wrong variable $value instead of $string:
if (get_magic_quotes_gpc()) { $value = stripslashes($string); }
should be
if (get_magic_quotes_gpc()) { $string = stripslashes($string); }
Are you sure you aren't calling mysql_real_escape_string more than once, each time you call it with escapable characters you will end up adding more and more slashes. You want to call it only once. Also, why are you also calling addcslashes? mysql_real_escape_string should be enough. If you call it only once, you should never have to call stripslashes on the data after retrieving it from the database.
You can't really tell if mysql_real_escape_string is applied more than once, I'd suggest going back and re-reading your code carefully, try debug printing the values just before they are inserted into the db to see if they are look 'over-slashed'.
Btw, if you are using prepared statements (e.g. via mysqli) you dont need to escape your strings, the DB engine does this for you, this could be the problem too.
Remove addslashes completely from all of your code. This is the leading cause for slashes being inserted into database.
function escape($string) {
if (get_magic_quotes_gpc()) {
$string = stripslashes($string);
}
return mysql_real_escape_string($string);
}
Always check if magic_quotes_gpc is enabled, if it is perform stripslashes and escape the data.
Escaped = "don\'t use addslashes"
When it goes into database the '\' is removed.
I have a mysql query which requires that parameters be enclosed in either "" or '',
if I have an array passed to this function:
function orderbyfield($column, array $selection)
{
// will it be alright (secure) to do this?
foreach ($selection as $s)
{
$s = '"' . $s . '"';
}
$string = implode(',', $selection)
return array($column, $string);
}
and pass it to
function generate_sql()
{
$fields = $this->orderbyfield(); // assuming the code is in a class
$sql = 'SELECT FIELDS FROM TABLE ORDER BY FIELD (' . $fields[0] . ',' . mysql_real_escape_string($fields[1]));
}
will there be any security issues with this approach?
EDIT
assume that code is in a class, made necessary addition of $this->
EDIT
typo on the foreach
As others have said you should be using mysql_real_escape_string at the point where you create the query string. Also, although the database may be able to cast between types, not all the variables need to be quoted in queries:
function enclose($val, $dbh)
{
if (($val==='') || (is_null($val))) {
return 'NULL';
}
// is it a number?
if (preg_match('/^[\+-]*\d+\.?\d*$/', $val)) {
return($val);
}
// its a string
return("'" . mysql_real_escape_string($val, $dbh) . "'");
}
The null handling might need to be tweaked. (the above is cut down from a generic interface I use which also reads the structure of the table using DESCRIBE to get hints on when to quote/use nulls etc)
C.
Because you are using the mysql_real_escape_string function, it is pretty safe as far as strings are concerned. See dealing with sql injection for more info.
You should add quotes arround your string, but there quotes inside your strings themselves should also be escaped -- this can be done using mysql_real_escape_string, mysqli_real_escape_string, or PDO::quote, depending on the kind of functions/methods you are using to connect to your database.
Doing this (As you are already doing -- which is nice) should prevent SQL injections (at least for string : you should also check that numerics are indeed corresponding to numerical data, for instance)
Another solution, maybe a bit easier once you get it, would be to use Prepared statements.
See :
PDO::prepare
or mysqli_prepare
(Those can't be used with the old mysql_* functions)
If you're using PDO's prepared statements, you do not have to worry about the escaping yourself. No quotes, no backslashes, no nothing.
According to the PHP manual, in order to make code more portable, they recommend using something like the following for escaping data:
if (!get_magic_quotes_gpc()) {
$lastname = addslashes($_POST['lastname']);
} else {
$lastname = $_POST['lastname'];
}
I have other validation checks that I will be performing, but how secure is the above strictly in terms of escaping data? I also saw that magic quotes will be deprecated in PHP 6. How will that affect the above code? I would prefer not to have to rely on a database-specific escaping function like mysql_real_escape_string().
Magic quotes are inherently broken. They were meant to sanitize input to the PHP script, but without knowing how that input will be used it's impossible to sanitize correctly. If anything, you're better off checking if magic quotes are enabled, then calling stripslashes() on $_GET/$_POST/$_COOKIES/$_REQUEST, and then sanitizing your variables at the point where you're using it somewhere. E.g. urlencode() if you're using it in a URL, htmlentities() if you're printing it back to a web page, or using your database driver's escaping function if you're storing it to a database. Note those input arrays could contain sub-arrays so you might need to write a function can recurse into the sub-arrays to strip those slashes too.
The PHP man page on magic quotes agrees:
"This feature has been DEPRECATED as
of PHP 5.3.0 and REMOVED as of PHP
5.4.0. Relying on this feature is highly discouraged. Magic Quotes is a
process that automagically escapes
incoming data to the PHP script. It's
preferred to code with magic quotes
off and to instead escape the data at
runtime, as needed."
Magic quotes were a design error. Their use is incompatible with retainnig your sanity.
I prefer:
if (get_magic_quotes_gpc()) {
throw new Exception("Turn magic quotes off now!");
}
Don't write code for compatibility with inherently broken setups. Instead defend aginst their use by having your code FAIL FAST.
I use the following code in the header file of my website to reverse the effects of magic_quotes:
<?php
// Strips slashes recursively only up to 3 levels to prevent attackers from
// causing a stack overflow error.
function stripslashes_array(&$array, $iterations=0) {
if ($iterations < 3) {
foreach ($array as $key => $value) {
if (is_array($value)) {
stripslashes_array($array[$key], $iterations + 1);
} else {
$array[$key] = stripslashes($array[$key]);
}
}
}
}
if (get_magic_quotes_gpc()) {
stripslashes_array($_GET);
stripslashes_array($_POST);
stripslashes_array($_COOKIE);
}
?>
Then I can write the rest of my code as if magic_quotes never existed.
"I would prefer not to have to rely on a database-specific escaping function like mysql_real_escape_string()"
Then use something like PDO. But you have to reverse the damage done by magic quotes anyway.
Put a requirement of PHP 5.2 or higher on your code and use the filter API. The filter_* functions access the raw input data directly (they don't ever touch $_POST etc.) so they're completely unaffected by magic_quotes_gpc.
Then this example:
if (!get_magic_quotes_gpc()) {
$lastname = addslashes($_POST['lastname']);
} else {
$lastname = $_POST['lastname'];
}
Can become this:
$lastname = filter_input(INPUT_POST, 'lastname');
Right, it's not the best way to do it and not the most secure. Escaping is best done in relation to what you are escaping for. If it is to store in a mysql database, use mysql_real_escape_string which takes into account other locales, character sets. For HTML, htmlentities. For use in code, escapeshellcmd, escapeshellarg. Yes, you probably need to stirpslashes first if magic quotes is on. But best not to count on it or use it.
Regarding using a database specific escaping function, you pretty much need to. I have found just using addslashes() to fail in rare cases with MySQL. You can write a function to escape which determines which DB you are using and then use the approriate escape function.
You may try this:
if (get_magic_quotes_gpc()) {
$_REQUEST = array_map('stripslashes', $_REQUEST);
$_GET = array_map('stripslashes', $_GET);
$_POST = array_map('stripslashes', $_POST);
$_GET = array_map('stripslashes', $_COOKIES);
}
"I would prefer not to have to rely on a database-specific escaping function like mysql_real_escape_string()"
Also addslashes can be tricked as well check out this post:
http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string
Your sample code is backwards, you should be doing the following:
if (get_magic_quotes_gpc()) {
$lastname = stripslashes($_POST['lastname']);
} else {
$lastname = $_POST['lastname'];
}
Note that this leaves your input data in a 'raw' state exactly as the user typed it - no extra backslashes and potentially loaded with SQL Injection and XSRF attacks - and that's exactly what you want. Then, you make sure you always use one of the following:
When echoing the variable into HTML, wrap it in htmlentities()
When putting it into mysql, use prepared statements or else mysql_real_escape_string() as a minimum.
When echoing the variable into Javascritpt code, use json_encode()
Joel Spolsky has some good starting advice in Making Wrong Code Look Wrong
Just found this over on the PHP manual pages, looks like a pretty clever way to strip em (deals with keys and values...):
if (get_magic_quotes_gpc())
{
$_GET = json_decode(stripslashes(json_encode($_GET, JSON_HEX_APOS)), true);
$_POST = json_decode(stripslashes(json_encode($_POST, JSON_HEX_APOS)), true);
$_COOKIE = json_decode(stripslashes(json_encode($_COOKIE, JSON_HEX_APOS)), true);
$_REQUEST = json_decode(stripslashes(json_encode($_REQUEST, JSON_HEX_APOS)), true);
ini_set('magic_quotes_gpc', 0);
}
Prepared statements of PDO and Mysqli are the better way to prevent SQL injection.
But if you are migrating a legacy code which is base on Magic Quotes for every SQL queries, you can refer yidas/php-magic-quotes for implementing Magic Quotes on the environment with PHP 5.4 above version.
https://github.com/yidas/php-magic-quotes