Magic quotes in PHP
Asked Answered
S

12

23

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().

Sirotek answered 21/10, 2008 at 0:50 Comment(0)
C
29

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."

Cantal answered 21/10, 2008 at 0:57 Comment(2)
Except that PHP6 never saw the light of day.Enneastyle
PHP did exist, it's just we weren't ready for itCynical
R
20

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.

Roundabout answered 21/10, 2008 at 8:43 Comment(1)
Awesome FAIL-FAST. Didn't know about it!Dunning
T
6

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.

Thorium answered 21/10, 2008 at 1:29 Comment(0)
K
2

"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.

Krenek answered 21/10, 2008 at 8:29 Comment(0)
S
2

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');
Sandry answered 14/1, 2009 at 3:16 Comment(0)
S
1

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.

Sodalite answered 21/10, 2008 at 1:0 Comment(0)
W
0

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.

Wickiup answered 21/10, 2008 at 6:47 Comment(0)
R
0

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);

    }
Russ answered 28/11, 2008 at 11:21 Comment(0)
M
0

"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

Mattie answered 14/1, 2009 at 2:41 Comment(0)
T
0

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

Trefor answered 14/1, 2009 at 3:42 Comment(0)
B
0

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);
}
Boulogne answered 22/4, 2010 at 6:5 Comment(1)
I'm the author of that note on the manual, just don't forget that since we're using the JSON_HEX_APOS constant this solution is only compatible with PHP 5.3 and above, see this question (#2078211) for more info.Octroi
S
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

Stearns answered 4/7, 2017 at 9:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.