Les magic quotes
Par Damien, dimanche 17 avril 2005 à 16:18 :: PHP :: #29 :: rss
Les magic quotes (guillements magiques) sont une fonctionnalité de PHP permettant de protéger automatiquement les données introduites dans un script PHP. Les magic quotes n'ont cependant rien de magique et s'avèrent en réalité bien ennuyants pour le développeur. Explications...
1- Introduction
Pour comprendre l'apparition des magic quotes, prenons un exemple de requête SQL :
INSERT INTO exemple(description) VALUES('Ma description')
Jusque là tout va bien, on crée un nouvel enregistrement dans la table exemple avec le texte Ma description dans le champ description.
Maintenant imaginons que l'on veuille créer un enregistrement avec le texte C'est un test. La requête devient :
INSERT INTO exemple(description) VALUES('C'est un test')
L'apostrophe pose problème, et la base de données nous renvoie une erreur ! La base de donnée pense en effet que la description s'arrête après la deuxième apostrophe rencontrée (après C).
Il faut donc "échapper" notre apostrophe.
2- Echappement des caractères réservés
En PHP, comme dans beaucoup d'autres languages, l'échappement des caractères réservés se fait à l'aide de l'antislash (\).
Exemples :
<?php // Un "mot" entre guillements $chaine1 = "Un \"mot\" entre guillements"; // ou alors... $chaine1 = 'Un "mot" entre guillements'; // C'est un test $chaine2 = 'C\'est un test'; // ou alors... $chaine2 = "C'est un test"; // J'affiche un antislash : \ $chaine3 = 'J\'affiche un antislash : \\'; ?>
En SQL, l'échappement des apostrophes est réalisé en les doublant. Notre dernière requête devient donc :
INSERT INTO exemple(description) VALUES('C''est un test')
Mais MySQL autorise également s'échappement par antislashs :
INSERT INTO exemple(description) VALUES('C\'est un test')
Les fonctions addslashes et stripslashes
La fonction addslashes() ajoute des antislashs devant les apostrophes ('), les guillemets ("), les antislashs (\) et le caractère NULL. Cette fonction permet donc de formater une chaine à envoyer à MySQL.
Exemple :
<?php $chaine = "Ceci est un texte composé d'une \"chaine"; $chaine .= "entre guillements\" et d'un antislash : \.\n"; $chaine .= "La fonction addslashes ajoute des antislashes devant "; $chaine .= "les antislashes, les apostrophes et les guillements."; /* affiche : Ceci est un texte composé d\'une \"chaine entre guillements\" et d\'un antislash : \\. La fonction addslashes ajoute des antislashes devant les antislashes, les apostrophes et les guillements. */ ?>
La fonction stripslashes() permet de faire l'inverse.
Les fonction *_escape_string
La fonction addslashes ne tiens néanmoins pas compte de toutes les spécificités de MySQL, et il est donc préférable d'utiliser la fonction mysql_real_escape_string() (PHP > 4.3.0), qui protégera également les \n et \r.
NB : Il existe également la fonction mysql_escape_string (PHP > 4.0.3) mais son usage est déprécié depuis PHP 4.3.0.
Il en va de même pour d'autres bases de données :
- SQLite : sqlite_escape_string
- PostgreSQL : pg_escape_string
3- Et les magic quotes dans tout ça ?
Les magic quotes permettent de faire automatiquement ce que fait la fonction addslashes, sur les données transmises par l'utilisateur (magic_quotes_gpc) et/ou provenant d'une source externe (magic_quotes_runtime). Lorsque les magic_quotes sont activées, tous les caractères ' (apostrophes), " (guillemets), \ (antislash) et NULL sont donc échappés par un antislash.
Il y a trois niveau de configuration des magic quotes.
magic_quotes_gpc
Echappe les données transmises par l'utilisateur (opérations GPC), c'est à dire les données transmises par les formulaires ($_GET, $_POST, $_REQUEST, $_FILES), et les cookies ($_COOKIES).
PHP4 échappe tout ce qui est dans le supertableau $GLOBALS (et donc incluant $_SERVER et $_ENV, mis à part $_SERVER['argv']), alors qu'il semble que PHP5 ne le fait pas.
Valeur par défaut : magic_quotes_gpc est généralement activé par défaut.
magic_quotes_runtime
Echappe les données provenant d'une source externe (base de données, fichier texte etc...).
Valeur par défaut : magic_quotes_runtime est généralement désactivé par défaut.
magic_quotes_sybase
Les apostrophes sont échappées par une autre apostrophe au lieu d'un antislash. Les guillements, antislashs et caractère NULL ne sont plus échappés. Ce comportement remplace le comportement de magic_quotes_gpc (si activé) et/ou de magic_quotes_runtime (si activé).
magic_quotes_sybase n'est pas uniquement lié à la base de données Sybase. MySQL permet l'échappement des apostrophes par antislash, mais la grande majorité des SGBD (Oracle par exemple) permet uniquement l'échappement par une autre apostrophe. magic_quotes_sybase est utile dans ces cas là, si vous activez les magic_quotes gpc et/ou runtime.
Valeur par défaut : magic_quotes_sybase est désactivé par défaut.
4- Utilité des magic quotes
Les magic quotes ont principalement été créées pour les débutants, tout d'abord par commodité, mais surtout par sécurité, pour éviter l'injection SQL.
Commodité
Les magic quotes permettent de contruire ses requêtes MySQL sans se soucier de l'échappement des données (qui est réalisé automatiquement). Cela permet d'apprendre plus rapidement.
Sécurité
Mais les magic quotes permettent surtout de sécuriser les applications des débutants, en évitant l'injection SQL.
Qu'est ce que l'injection SQL ?
Prenons un exemple d'identification très basique :
<?php $sql = "SELECT id_membre FROM membres "; $sql .= "WHERE identifiant = '" . $_POST['identifiant'] . "' "; $sql .= "AND motpasse = '" . $_POST['motpasse'] . "'"; ?>
Si le visiteur entre les valeurs toto et superpass dans le formulaire, la requête SQL donnera :
SELECT id_membre FROM membres WHERE identifiant = 'toto' AND motpasse = 'superpass'
Jusque là pas de problème, la base de données retournera un résultat si l'identifiant et le mot de passe sont corrects.
Mais maintenant imaginons qu'un petit malin entre admin' OR ' pour identifiant (partons du principe que admin est l'identifiant de l'administrateur) et passbidon pour mot de passe. Si les magic_quotes_gpc ne sont pas activées, la requête SQL devient :
SELECT id_membre FROM membres WHERE identifiant = 'admin' OR '' AND motpasse = 'passbidon'
Que se passe t'il ? Le visiteur s'identifie en tant qu'administrateur ! Et oui, le mot de passe n'a aucune influence pour la base de données si la condition avant le OR (identifiant = 'admin') est vérifiée.
Il faut donc échapper notre login et notre mot de passe (avec addslashes ou mysql_real_escape_string). Mais soyons réalistes, on se préoccupe rarement de ce genre de subtilité lorsqu'on débute, d'où l'intérêt des magic quotes.
5- Pourquoi ne pas utiliser les magic quotes ?
Les magic quotes ont cependant plein de défauts...
Chaque SGBD a ses propres spécificités
Les magic quotes ne tiennent pas compte des spécificités de chaque SGBD. Certes, la directive magic_quotes_sybase permet d'échapper les apostrophes par une autre apostrophe au lieu d'un antislash, pour Oracle et PostgreSQL par exemple, mais ce n'est pas suffisant.
Par exemple, pour MySQL, il est préférable d'utiliser la fonction mysql_real_escape_string() plutôt que les magic quotes (ou la fonction addslashes). Cette fonction permet également d'échapper \n et \r, en plus des apostrophes, guillements et compagnie. C'est mieux.
Performances
Toutes nos données ne sont pas systématiquement placées dans une base, il est donc inutile de toutes les protéger ! Appeler les fonctions d'échappement en fonction de ses besoins est beaucoup plus efficace.
Pas toujours pratique
Comme toutes les données n'ont pas forcément besoin de protection, il est souvent désagréable de voir des données protégées là où ça ne sert à rien. Par exemple, lorsque vous envoyez un formulaire par email, il faut faire appel à la fonction stripslashes pour éviter de voir de nombreux antislashes parsemer notre message. C'est ennuyant et nuie là aussi aux performances.
Portabilité
Les magic quotes peuvent être activées ou désactivées suivant les serveurs. Développer une application se basant exclusivement sur les magic quotes nuie à sa portabilité.
6- Désactiver les magic quotes ...
Depuis le fichier php.ini du serveur
Idéalement, si vous avez accès à la configuration du serveur, vous pouvez désactiver les magic quotes dans le fichier php.ini (un peu avant le milieu du fichier, aux alentours de la ligne 380).
; Magic quotes ; ; On = activé ; Off = désactivé ; Magic quotes for incoming GET/POST/Cookie data. magic_quotes_gpc = Off ; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc. magic_quotes_runtime = Off ; Use Sybase-style magic quotes (escape ' with '' instead of \'). magic_quotes_sybase = Off
Depuis un fichier .htaccess
Sinon, vous pouvez utiliser un fichier .htaccess :
php_flag magic_quotes_gpc Off php_flag magic_quotes_runtime Off php_flag magic_quotes_sybase Off
A l'exécution
Afin d'écrire du code portable sur tous les environnements, et où vous ne pouvez pas forcément modifier la configuration du serveur, voici un exemple de désactivation des magic quotes à l'exécution.
<?php function fix_magic_quotes ($var = NULL, $sybase = NULL) { // si $sybase n'est pas spécifié, on regarde la configuration ini { } // si $var n'est pas spécifié, on corrige toutes les variables superglobales { // si les magic_quotes sont activées { // tableaux superglobaux a corriger { // PHP5 semble ne pas changer _ENV et _SERVER // les magic_quotes ne changent pas $_SERVER['argv'] } foreach ( $array as $var ) { $GLOBALS[$var] = fix_magic_quotes ($GLOBALS[$var], $sybase); } { $_SERVER['argv'] = $argv; } // désactive les magic quotes dans ini_set pour que les // scripts qui y sont sensibles fonctionnent } // idem, pour magic_quotes_sybase if ( $sybase ) { } // désactive magic_quotes_runtime return TRUE; } // si $var est un tableau, appel récursif pour corriger chaque élément { foreach ( $var as $key => $val ) { $var[$key] = fix_magic_quotes ($val, $sybase); } return $var; } // si $var est une chaine on utilise la fonction stripslashes, // sauf si les magic_quotes_sybase sont activées, dans ce cas on // remplace les doubles apostrophes par des simples apostrophes { } // sinon rien return $var; } fix_magic_quotes(); ?>
7- ... et protéger ses données
Mais une fois les magic quotes désactivées, faites attention de bien penser à protéger vos données avant insertion dans une base de données.
Voici un exemple :
<?php /* CREATE TABLE `exemple` ( `description` varchar(150) NOT NULL default '' ); */ // si formulaire envoyé { // connexion à la base de données // protection des données // insertion des données $sql = "INSERT INTO `exemple` (`description`) VALUES ('".$description."')"; // fin } ?> <!-- Formulaire --> <form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>"> <fieldset> <legend>Exemple</legend> <p> <label for="description">Description :</label> <input type="text" name="description" size="50" maxlength="150" /> </p> <p><input type="submit" name="envoi" value="Ajouter" /></p> </legend> </fieldset> </form>
8- Conclusion
J'espère que ce tutorial ne vous a pas trop embrouillé, et que le sujet commence à s'éclaircir.
Pour résumer, les magic quotes ont été créées pour les débutants, et font de PHP un des languages les moins sensibles à l'injection SQL. Néanmoins, une fois que vous comprenez bien leur fonctionnement, il est préférable de les désactiver et de protéger vos données vous même à l'aide des fonctions d'échappement de votre SGBD. C'est plus efficace et plus portable !

Commentaires
1. Le jeudi 5 mai 2005 à 20:55, par Pouille
2. Le vendredi 6 mai 2005 à 09:24, par Damien
3. Le jeudi 11 août 2005 à 02:44, par [Free]
4. Le dimanche 14 août 2005 à 23:27, par chmouc
5. Le mercredi 24 août 2005 à 13:59, par Tornade
6. Le jeudi 20 octobre 2005 à 14:50, par McBenny
7. Le jeudi 5 janvier 2006 à 13:01, par nza2k
8. Le dimanche 5 mars 2006 à 19:05, par gomoz
9. Le jeudi 15 juin 2006 à 16:17, par Artotal
10. Le vendredi 16 juin 2006 à 14:30, par Captain Nemo
11. Le samedi 25 novembre 2006 à 17:08, par L
12. Le mardi 16 janvier 2007 à 13:08, par ChoOo7
13. Le lundi 26 février 2007 à 15:38, par DJIKAIN
14. Le jeudi 1 mars 2007 à 14:34, par Enzo.Snow
15. Le dimanche 18 mars 2007 à 10:22, par php
16. Le dimanche 6 mai 2007 à 21:53, par generateur
17. Le lundi 14 mai 2007 à 13:34, par Peter
18. Le jeudi 31 mai 2007 à 13:35, par chels75
19. Le jeudi 23 août 2007 à 12:17, par Poker
20. Le samedi 5 janvier 2008 à 00:42, par test qi
21. Le vendredi 8 février 2008 à 01:15, par Nothing
22. Le jeudi 14 février 2008 à 12:10, par fab
23. Le mardi 11 mars 2008 à 14:31, par immobilier
24. Le vendredi 9 mai 2008 à 14:04, par Lamy
25. Le dimanche 1 février 2009 à 02:40, par Sacapuss
26. Le dimanche 21 juin 2009 à 17:57, par camelus68
27. Le mardi 23 juin 2009 à 11:24, par Melizandre
28. Le dimanche 5 juillet 2009 à 00:11, par Jihed
29. Le mardi 1 juin 2010 à 20:48, par test de qi
30. Le mardi 3 août 2010 à 17:46, par Le boss
Ajouter un commentaire