Wat is magic quotes en hoe/wanneer gebruik ik addslashes?

Trefwoorden: PHP, magic_quotes_gpc, addslashes, stripslashes

1. Inleiding


Bijna iedere webmaster die van tijd tot tijd wel eens een moment spendeert aan PHP in combinatie met een database (bijvoorbeeld MySQL) is er al eens mee geconfronteerd geweestů Je maakt een, al dan niet strikt afgelijnd en netjes opgemaakt, formulier om bijvoorbeeld nieuwsberichten weg te schrijven naar een database. Je test dit script met enkele zetteksten (bijvoorbeeld een Lorem Ipsum) en merkt geen fouten op. Daarna besluit je eens een tekst met wat meer exotische tekens of gewoon accenten in te voegen en plots werkt je script niet meer...

2. En toen begonnen de problemen...


Een eenvoudige zin als Pa's wijze lynx bezag vroom het fikse aquaduct produceert opeens een foutmelding als You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near ''Pa's wijze lynx bezag vroom het fikse aquaduct')' at line 1.

De oplossing voor dit probleem is al even eenvoudig als hij lang is: addslashes(). Addslashes zorgt ervoor, zoals je reeds kon vermoeden, dat er aan een opgegeven string automatisch slashes worden toegevoegd, indien nodig. In ons voorbeeld zou er een backslash moeten worden toegevoegd om de apostrof net na Pa te escapen. De reden hiervoor is eveneens eenvoudig: aangezien we een insert query uitvoeren met tekst in, dienen we aan te geven waar een string begint en eindigt. Dit doen we door gebruik te maken van een apostrof aan zowel het begin als het einde van die string. Als er ergens in onze string reeds een apostrof voorkomt, denkt de parser dat onze string daar eindigt. Dit is echter niet het geval, want er kunnen nog heel wat tekens volgen... Om deze foutmelding te voorkomen, voegen we dus een backslash toe voor de apostrof, zodat de parser weet dat hij het teken niet moet interpreteren als zijnde het einde van onze string.

So far, so good. Je hebt dus je script geschreven en uitvoerig getest in je (mogelijk lokale) testomgeving, waar het werkte zonder ook maar een krimp te geven. Na in achtneming van de testperiode besluit je het script in te zetten in je productieomgeving. Bij het ophalen van je weggeschreven gegevens, staat er opeens Pa\'s wijze lynx bezag vroom het fikse aquaduct. Het lijkt wel alsof ons escapekarakter niet herkend en gewoon ingevoegd werd. Hoe kan dat? Alles werkte toch naar behoren tijdens de testfase?

3. Waarom het foutloopt...


Indien je de code van het script niet hebt aangepast, komt PHP's Magic Quotes zich waarschijnlijk met de verwerking van het invoegen bemoeien. In het volle parse-geweld besluit deze functionaliteit om alle strings die via GET, POST of Cookie worden doorgegeven automatisch te voorzien van de addslashes-functie. Hoewel de bedoeling van het PHP-team initieel zeer goed was, blijkt de idee in de praktijk niets dan problemen op te leveren. In een omgeving waar magic_quotes_gpc (magic quotes voor GET, POST & Cookie) worden er automatisch backslashes geplaatst voor een enkel aanhalingsteken, voor een dubbel aanhalingsteken, voor een backslash en voor NUL. Doordat we zelf ook al een addslashes-functie hebben gebruikt, wordt onze string twee maal ge-escaped. Pa's wijze lynx zal worden verwerkt als Pa\\'s wijze lynx en dat is verre van wat we willen.

4. De redding!


Maar ik kan toch gewoon stripslashes() toepassen op de string wanneer ik deze uit de database haal, waarna alles terug in orde komt?. Inderdaad, dat is een mogelijkheid. Deze oplossing bezorgt je echter wel extra (volkomen nutteloze!) karakters in je database, om nog maar te zwijgen van de problemen die je zal krijgen wanneer je jouw code gaat verplaatsen naar een server waar magic quotes voor gpc uitgeschakeld staat... Je zal dus elke string die wordt doorgegeven moeten nakijken, verre van praktisch!

Beeld je maar eens in dat je een select query uitvoert, bijvoorbeeld om een waarde te zoeken in je database.

CODE
  1. $sql = "SELECT * FROM tbl WHERE tekst='Pa's wijze lynx...'";


Is het deel van de code na tekst= ingetypt door een bezoeker of is dit vast gecodeerd? Wat indien je twee SQL-statements gebruikt? EÚn voor een zoekquery die een gebruiker intypt en ÚÚn default query? Je kan dan onmogelijk addslashes() toevoegen in je query-functie, tenzij je zelf ook de escapetekens gaat intypen. Dit laatste is natuurlijk not done; dit zijn dingen die we dienen over te laten aan PHP, waarover we zelf niet hoeven te denken.

De oplossing voor dit alles is nochtans redelijk eenvoudig: zorg ervoor dat je nooit stripslashes() hoeft te gebruiken! Zorg ervoor dat je strings slechts eenmalig worden voorzien van escapetekens, enkel om te toe te zien dat je queries veilig uitgevoerd kunnen worden. Gelukkig biedt PHP ons de functionaliteit om te kijken of magic quotes voor gpc al dan niet aanstaat. Er hoeft zelfs niet eens veel code aan te pas te komen:

PHP
  1. <?php
  2.  
  3. {
  4.    
  5.     echo ("Magic quotes voor gpc staat aan");
  6.    
  7. }
  8. else
  9. {
  10.    
  11.     echo ("Magic quotes voor gpc staat uit");
  12.    
  13. }
  14.  
  15. ?>


Nu dat we weten hoe we kunnen nakijken of magic quotes voor gpc aanstaat, is het relatief eenvoudig om deze informatie ook te gebruiken. Al wat we nodig hebben om op elke server een string correct te escapen, is onze eigen home made addslashes-functie. Klinkt toch goed hÚ? Ook die code krijg je van me cadeau:

PHP
  1. <?php
  2.  
  3. function gecontroleerdeAddSlashes($string)
  4. {
  5.    
  6.     // Indien magic quotes voor gpc aanstaat...
  7.     if (get_magic_quotes_gpc() == 1)
  8.     {
  9.        
  10.         // ... dienen we de opgegeven string niet nogmaals te voorzien van escapekarakters.
  11.         return $string;
  12.        
  13.     }
  14.     // Indien magic quotes voor gpc niet aanstaat...
  15.     else
  16.     {
  17.        
  18.         // ... voorzien we de opgegeven string eigenhandig van escapekarakters.
  19.         return addslashes($string);
  20.        
  21.     }
  22.  
  23. }
  24. ?>


Indien je nu een string wil escapen, gebruik je niet langer de oude werkwijze:

PHP
  1. <?php
  2.  
  3. $string = addslashes($string);
  4.  
  5. ?>


Je maakt gebruik van onze eigen functie:

PHP
  1. <?php
  2.  
  3. $string = gecontroleerdeAddSlashes($string);
  4.  
  5. ?>


Zorg ervoor dat je bovenstaande techniek overal gebruikt en normaal gezien zal je nergens nog stripslashes() moeten gebruiken bij het uitlezen van gegevens uit je database.

5. Magic quotes uitzetten



Indien je op je server gebruik kan maken van .htaccess, kan je magic quotes voor gpc eigenhandig uitschakelen.

5.1. Via .htaccess

5.1.1. PHP 3 (ge´nstalleerd als module)

CODE
  1. <IfModule mod_php3.c>
  2. php3_flag magic_quotes_gpc off
  3. </IfModule>


5.1.2. PHP 4 (ge´nstalleerd als module)

CODE
  1. <IfModule mod_php4.c>
  2. php_flag magic_quotes_gpc off
  3. </IfModule>


5.1.3. PHP X

Op deze manier zal je echter voor elke PHP-installatie een nieuw stuk code moeten voorzien. Eenvoudiger is om gewoon volgende code in een .htaccess te typen en dit bestand te plaatsen in de map waarin je wilt dat magic quotes voor gpc uit wordt geschakeld.

CODE
  1. php_flag magic_quotes_gpc off


5.2. Via php.ini

Je kan er echter ook voor opteren om reeds bij het laden van de PHP-parser magic quotes voor gpc uit te schakelen. Zoek hiervoor het bestand php.ini en open het in een plain text editor (zoals bijvoorbeeld notepad/kladblok). Blader dan door dit bestand tot je de regel met de tekst magic_quotes_gpc = tegenkomt. Zorg ervoor dat achter het gelijkheidsteken het woord off staat.

5.3. Via magic_quotes_runtime()

In sommige gevallen is het mogelijk dat magic_quotes_gpc aanstaat via magic_quotes_runtime(). Dit is echter eerder uitzondering dan regel. Of magic_quotes_runtime() gebruikt wordt, kan je nakijken via phpinfo() of via get_magic_quotes_runtime().

Uitschakelen kan heel eenvoudig via:

PHP


6. Tot slot


Op de hele tekst bestaan nog enkele uitzonderingen. Zo zal get_magic_quotes_gpc() de waarde TRUE teruggeven, maar dubbele aanhalingstekens, backslashes en NUL's niet voorzien worden van escapetekens indien magic_quotes_sybase() aanstaat. Indien je gebruik maakt van sybase, heb je normaal wel reeds wat ervaring met PHP en zal je ook eenvoudig de hoger vermelde voorbeelden kunnen aanpassen. Voor zij die ge´nteresseerd zijn in sybase is er steeds meer lectuur te vinden op deze pagina.Dit artikel werd geschreven door Martijn op dinsdag 14 februari 2006 om 10:19 en werd sindsdien 10762 keer gelezen.

  • Pagina
  • 1 van 1

Bericht geplaatst door MontyP op woensdag 1 maart 2006 om 02:37:10.
MontyP's avatar
Multiviteit: 273
Ik heb er nog aan toegevoegd, om sql injections te vermijden:

PHP
  1.  
  2. <?
  3. function formatStringForDatabase($string)
  4. {
  5.     if (get_magic_quotes_gpc() == 1)
  6.     {
  7.         return htmlspecialchars(strip_tags($string))
  8.     }
  9.     else
  10.     {
  11.         return addslashes(htmlspecialchars(strip_tags($string)));
  12.     }
  13. }
  14. ?>
  15.  


strip_tags verwijdert alle html tags.
htmlspecialchars verwijdert alle tekens zoals < en > die nog overblijven na strip_tags, voor het geval een hacker probeert de html code te manipuleren via een form. Makes sense hopelijk.
Bericht geplaatst door Martijn op vrijdag 10 maart 2006 om 09:10:00.
Martijn heeft nog geen avatar toegevoegd
Multiviteit: 13785
Beheerder
Is inderdaad zeker en vast aan te raden, maar misschien best BUITEN de functie. De reden waarom je dit best doet, is gewoon om de functionaliteit gescheiden te houden :).

Stripslashes is stripslashes en niet secureString() of zoiets. Is natuurlijk grotendeels persoonlijke opinie hÚ; de functie die je schreef is perfect bruikbaar!
Met vriendelijke groeten,
Martijn Wouters
  • Pagina
  • 1 van 1