Magic quotes may have been one of the biggest sins of the past in PHP, and we should celebrate the fact that now, ultimately, it is gone from PHP. Magic quotes are a perfect example of how long it can take to undo a broken feature that was introduced into a programming language.
The basic idea of magic quotes, as always, was a good one. As we all know, user input is to be considered dangerous, at least from a security perspective. In fact, a healthy level of security paranoia is to consider every request an attack until the application manages to prove otherwise. With regards to security, we all have heard about the basic rule "filter input, escape output".
SQL injection attacks, also well-known, can be extremely dangerous. Not only can they enable an attacker to read arbitrary data from our database, they might even be able to modify existing data. One textbook example for a SQL injection, for example, is to use the following username in a login screen:
' OR 1=1; --
If the code builds a SQL query to retrieve the user's ID from a MySQL database like this:
$sql = 'SELECT id FROM user WHERE username=' . $username . ' AND password=' . $password ; |
the resulting SQL will be:
SELECT id FROM user WHERE username='' OR 1=1; -- AND password=...
It does not really matter which password we enter, we have just gained access to the system without providing proper credentials, and are impersonating the first user listed in the user table. To make things worse, this is often the system administrator.
Magic quotes were conceived to fix this problem, and it utterly failed in trying so. The idea was to automatically escape incoming data to protect against SQL injections. With magic quotes enabled, single quotes were escaped with a backslash, rendering the described attack useless, because the SQL statements now expands to:
SELECT id FROM user WHERE username='\' OR 1=1; -- AND password=...
This SQL statement is syntactically incorrect, and cannot be executed. While, depending on how the application deals with such an error, there still may be annoying side effects, at least it are not vulnerable against a SQL injection attack.
Or so it would seem. One big problem with magic quotes is that they could be turned on or off in php.ini
. This means that application developers safely cannot rely on the fact that data has been escaped. So in fact, magic quotes made our world insecure because either application developers relied on PHP to automatically escape data, or it would lead to broken data because the application would escape the data again.
But there are even more problems with magic quotes. The SQL standard requires a single quote to be escaped with another single quote rather than a backslash. MySQL traditionally also accepts a backslash as the escape character, but newer versions of MySQL that are stricter in following the SQL standards, this is not guaranteed to work anymore. Current MySQL versions, for example, come with strict mode enabled by default.
The main conceptual problem with magic quotes, however, is that this approach escapes the data too early. Correct escaping depends on the context. In the SQL context, single quotes are dangerous and must be escaped. In HTML context, the greater than and less than sign are dangerous and must be escaped. In other contexts, yet other characters must be escaped. Escaping too early without knowing the output context can never be secure.
Since an application could not safely rely on magic quotes to be enabled, it had to escape data explicitly but itself. To avoid double escaping, however, the application would have to detect whether magic quotes were enabled. And to be able to escape data correctly according to the output context, the application would in fact have to undo any escaping that PHP had magically done. This was necessary because it was not possible to disable magic quotes at runtime.
To sum it up, magic quotes is a feature that, in hindsight, nobody ever never should have used. In fact, most of what made up the functionality has already been deprecated in PHP 5.3 and PHP 5.4. The function set_magic_quotes_runtime
and its alias magic_quotes_runtime
, which has been deprecated since PHP 5.3, has finally been removed in PHP 7. Starting with version 5.4, PHP has raised an E_CORE_ERROR
when this function was called. Trying to use this function in PHP 7 yields a fatal error:
Fatal error: Uncaught Error:
Call to undefined function set_magic_quotes_runtime() in ...
The two php.ini
settings that control the magic quotes behavior, magic_quotes_gpc
and magic_quotes_runtime
have already been removed in PHP 5.4. Trying to set them in php.ini
will lead to a fatal error:
PHP Fatal error:
Directive 'magic_quotes_runtime' is no longer available in PHP in Unknown on line 0
Error messages "in Unknown on line 0" usually relate to parsing php.ini
on PHP startup.
The function get_magic_quotes_runtime()
still exists, but will always return false
.
If you upgrade to PHP 7 from a recent PHP 5 version, magic quotes should not be a problem for you. If you upgrade from PHP 5.3, make sure that your code does not rely on magic quotes. If your code does, you probably have some serious security issues to deal with before you should proceed with the upgrade.
The proper fix is to escape data where its is used, and escape it for the context it is being used in. When it comes to escaping, you should not give in to a quick fix, but make sure that you have a solid solution in place. Security does not come for free, and it cannot just be built into the language.