[PHP] Escapen mbt. MySQL

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • mcdronkz
  • Registratie: Oktober 2003
  • Laatst online: 16-04 12:44
Ik heb nu het één en ander gelezen over escapen, maar er ontgaat me toch nog iets.

In PHP staat magic_quotes_gpc standaard aan als ik het goed begrepen heb. Ik heb inmiddels besloten om deze maar standaard uit te zetten, omdat ik bepaal wat er wel en niet ge-escaped moet worden, en niet m'n server.

Echter, nu zijn er een aantal mogelijkheden over om bepaalde tekens te escapen. Eén daarvan is addslashes(), en de ander is mysql_real_escape_string().

Wat is nu eigenlijk het verschil tussen die twee ?

En verder, ik geloof dat backquotes (`) nooit ge-escaped worden. Is dat niet een kwalijke zaak ? Volgens mij is er dan zeker nog een risico wbt. SQL injection voor de mensen die standaard backquotes gebruiken (en dat zijn er nogal wat).

Dan zitten we nog met integers, het liefst ga je die natuurlijk niet tussen quotes zetten, het zijn immers integers. Maar stel je hebt iets als dit;

PHP:
1
<?php mysql_query("SELECT COUNT(*) FROM tabel WHERE prijs = ".$_GET['id']." ORDER BY prijs DESC"); ?>


Dan kan nogsteeds het volgende aangeroepen worden;

code:
1
http://www.example.com/index.php?id=1 OR 1 = 1; DROP TABLE tabel; SELECT * FROM tabel


Bij wijze van spreken. Bij mij krijg ik er alsnog een SQL syntax error op, maar dat even terzijde. Normaal gesproken werkt dit gewoon lijkt me.

Kom je er dan toch uiteindelijk op uit dat je integers tussen enkele quotes of backquotes moet gaan plaatsen ?

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
mcdronkz schreef op maandag 28 april 2008 @ 22:17:
Echter, nu zijn er een aantal mogelijkheden over om bepaalde tekens te escapen. Eén daarvan is addslashes(), en de ander is mysql_real_escape_string().
Lees de documentatie :) http://php.net/addslashes en http://php.net/mysql_real_escape_string:

Returns a string with backslashes before characters that need to be quoted in database queries etc. These characters are single quote ('), double quote ("), backslash (\) and NUL (the NULL byte).
vs
Escapes special characters in the unescaped_string , taking into account the current character set of the connection so that it is safe to place it in a mysql_query(). If binary data is to be inserted, this function must be used.
mysql_real_escape_string() calls MySQL's library function mysql_real_escape_string, which prepends backslashes to the following characters: \x00, \n, \r, \, ', " and \x1a.


De eerste escaped een kleiner aantal tekens, puur ter "escape", De laatste is specifiek bedoeld voor het veilig(er) stellen van je sql data.
En verder, ik geloof dat backquotes (`) nooit ge-escaped worden. Is dat niet een kwalijke zaak ? Volgens mij is er dan zeker nog een risico wbt. SQL injection voor de mensen die standaard backquotes gebruiken (en dat zijn er nogal wat).
Met backquotes kan je afaik geen injection veroorzaken hoor...
Dan zitten we nog met integers, het liefst ga je die natuurlijk niet tussen quotes zetten, het zijn immers integers. Maar stel je hebt iets als dit;

PHP:
1
<?php mysql_query("SELECT COUNT(*) FROM tabel WHERE prijs = ".$_GET['id']." ORDER BY prijs DESC"); ?>


Dan kan nogsteeds het volgende aangeroepen worden;

code:
1
http://www.example.com/index.php?id=1 OR 1 = 1; DROP TABLE tabel; SELECT * FROM tabel
Deze is meer voor je logica. Je verwacht een id. Je id specificeer je als een integer. Je eerste check in je controller lijkt me dus ook of je id een integer is :)

Acties:
  • 0 Henk 'm!

  • japaveh
  • Registratie: Maart 2003
  • Laatst online: 20-09 20:47

japaveh

Jield BV

mcdronkz schreef op maandag 28 april 2008 @ 22:17:
Kom je er dan toch uiteindelijk op uit dat je integers tussen enkele quotes of backquotes moet gaan plaatsen ?
Nee, vziw mag dat juist helemaal niet eens. Ik cast altijd via intval naar een integer in de query als het een int moet zijn.

Je kunt ook voordat je de query uitvoert via is_numeric checken of de waarde uit je $_GET inderdaad een getalletje is. Is die waarde gelijk aan false, dan return je het script en geef je een foutmelding

edit: Wat mithras zegt dus, maar dan meer toegepast :)

[ Voor 7% gewijzigd door japaveh op 28-04-2008 22:25 ]

Solo Database: Online electronic logbook and database system for research applications


Acties:
  • 0 Henk 'm!

  • ChessSpider
  • Registratie: Mei 2006
  • Laatst online: 01-08 19:01
japaveh schreef op maandag 28 april 2008 @ 22:24:
[...]

Nee, vziw mag dat juist helemaal niet eens. Ik cast altijd via intval naar een integer in de query als het een int moet zijn.

Je kunt ook voordat je de query uitvoert via is_numeric checken of de waarde uit je $_GET inderdaad een getalletje is. Is die waarde gelijk aan false, dan return je het script en geef je een foutmelding

edit: Wat mithras zegt dus, maar dan meer toegepast :)
En bij is_numeric moet je oppassen met SQL, zie:
http://nl2.php.net/manual/en/function.is-numeric.php#76094

Acties:
  • 0 Henk 'm!

  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

Met Backticks kunt ge wel u query om zeep helpen, en zo een error op het scherm triggeren, wat wel weer belangrijke hack info kan zijn.

Kijk eens naar www.php.net/PDO .

Going for adventure, lots of sun and a convertible! | GMT-8


Acties:
  • 0 Henk 'm!

  • mcdronkz
  • Registratie: Oktober 2003
  • Laatst online: 16-04 12:44
japaveh schreef op maandag 28 april 2008 @ 22:24:
[...]

Nee, vziw mag dat juist helemaal niet eens.
Nee, dat lijkt me ook niet, toch zie je dat het maar al te vaak gebeurt omdat mensen denken dat het een extra bescherming tegen SQL injection biedt, en MySQL heeft er verder niet zoveel problemen mee.

Acties:
  • 0 Henk 'm!

  • japaveh
  • Registratie: Maart 2003
  • Laatst online: 20-09 20:47

japaveh

Jield BV

Hmm, dat is wel een interessante, dat wist ik niet tnx. Je moet natuurlijk steeds is_numeric gebruiken bij form-elements alhoewel er een work-around bestaat zodat je is_int kunt gebruiken
code:
1
if ($_POST["number"] == (int)$_POST["number"]) $_POST["number"] = (int)$_POST["number"];

of
code:
1
if (($_POST["number"] + 1 - 1) == $_POST["number"]) ...

Feit blijft dat je de uitendelijke waarde van je $_GET variabele atlijd moet checken voordat hij de query ingaat.

Solo Database: Online electronic logbook and database system for research applications


Acties:
  • 0 Henk 'm!

  • mcdronkz
  • Registratie: Oktober 2003
  • Laatst online: 16-04 12:44
but 0123 without quotes cannot be inserted into SQL
Dat mis ik even, ik kan juist prima 0123 zonder quotes inserten, '0123' (dus met quotes) wil dan weer niet.

Mijn fout, ik kan het allebei inserten. Hij ziet 't gewoon als 123.

[ Voor 18% gewijzigd door mcdronkz op 28-04-2008 22:43 ]


Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Simpelste methode is gewoon checken of wat je wilt wegschrijven ook is wat je wilt wegschrijven. Even uit mijn hoofd is mysql_real_escape_string alleen nodig bij char / varchar / text velden.

Alle enums, int / float / decimal / datetime velden zijn perfect in je app te valideren.
Kijk ook goed hoe je het valideert, casten naar int zegt niets over of het goed in je database is gezet, als jij een float / decimal / string met een getal voor de komma naar intval stuurt krijg je altijd een uitkomst, maar niet altijd wat je verwacht.
Een intval (2.2371) geeft geen error als je dbase op int staat, maar in je dbase heb je dan alleen een 2 staan.

Acties:
  • 0 Henk 'm!

Verwijderd

mysql_escape_string zegt het zelf al... strings...
voor ints heel simpel.

[code=php]<?
if(is_numeric($i))
{
mysql_query("insert into something (intveld) values (".(int)$i.")");
}
?>
weet je altijd dat hij numeric is, zal hij nooit een fout geven, etc.
Snake schreef op maandag 28 april 2008 @ 22:28:
Met Backticks kunt ge wel u query om zeep helpen, en zo een error op het scherm triggeren, wat wel weer belangrijke hack info kan zijn.

Kijk eens naar www.php.net/PDO .
een beetje fatsoenlijke php code zal nooit een error direct op het scherm geven. enkel een nette foutmelding. zorg altijd dat je je error handler veranderd naar een custom functie en bijv dmv een IP check kijken of je wel of geen debug data naar voren wilt brengen.

Acties:
  • 0 Henk 'm!

  • mcdronkz
  • Registratie: Oktober 2003
  • Laatst online: 16-04 12:44
Ik ga me ook maar eens verdiepen in prepared statements, dat maakt het geheel ook net wat leesbaarder. PDO lijkt me wel okay, maar ik vraag me af mysqli niet een stuk lichter is. Maar dat is verder niet echt relevant voor dit topic.

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Verwijderd schreef op maandag 28 april 2008 @ 23:26:
mysql_escape_string zegt het zelf al... strings...
voor ints heel simpel.

[code=php]<?
if(is_numeric($i))
{
mysql_query("insert into something (intveld) values (".(int)$i.")");
}
?>
weet je altijd dat hij numeric is, zal hij nooit een fout geven, etc.
Ok, nu $i=2.2371, wat is de uitkomst van deze oefening en wat staat er in de dbase? Oh wacht, ik mocht geen floats hieraan meegeven ok $i=2.24 dan? Oh, mag ik ook geen decimal(4,2) meegeven...
[...]
een beetje fatsoenlijke php code zal nooit een error direct op het scherm geven. enkel een nette foutmelding. zorg altijd dat je je error handler veranderd naar een custom functie en bijv dmv een IP check kijken of je wel of geen debug data naar voren wilt brengen.
Hmmm, ik zou ipv ip-check gewoon standaard alles ook mee laten lopen naar een error-log. Kan je ook nog iets met klanten die melden dat ze een uur geleden een fout kregen...

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

mithras schreef op maandag 28 april 2008 @ 22:23:
Met backquotes kan je afaik geen injection veroorzaken hoor...
Wel als je een tabel- of veldnaam uit gebruikersinput samenstelt. Wat, IMO, sowieso geen goed plan is in de meeste gevallen.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 18-09 16:28

Bosmonster

*zucht*

Verwijderd schreef op maandag 28 april 2008 @ 23:26:
mysql_escape_string zegt het zelf al... strings...
voor ints heel simpel.

[code=php]<?
if(is_numeric($i))
{
mysql_query("insert into something (intveld) values (".(int)$i.")");
}
?>
weet je altijd dat hij numeric is, zal hij nooit een fout geven, etc.


[...]


een beetje fatsoenlijke php code zal nooit een error direct op het scherm geven. enkel een nette foutmelding. zorg altijd dat je je error handler veranderd naar een custom functie en bijv dmv een IP check kijken of je wel of geen debug data naar voren wilt brengen.
Waarom zou je eerst controleren als je iets cast in PHP? Cast gewoon naar dat wat het moet zijn (int, float, wat je verwacht). PHP gaat daar soepel mee om en converteert indien nodig.

(int) 'abc' geeft bijvoorbeeld gewoon 0.

Die soepelheid kun je gewoon gebruiken lijkt me. Wat ik meestal doe is casten en vervolgens (indien nodig) controleren of de waarde die eruitkomt nog representatief is, bijvoorbeeld:

PHP:
1
2
3
4
$ID = isset ($_GET['ID']) ? (int) $_GET['ID'] : 0;

if ($ID == 0)
   // er klopt iets niet, doe redirect ofzo of geef foutmelding


Dat is een eenvoudige, en volgens mij 100% veilige, check als het om ints gaat of floats. Voor string is het en kwestie van mysql_real_escape_string() inderdaad voor gebruik in database.

[ Voor 13% gewijzigd door Bosmonster op 29-04-2008 10:41 ]


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Lees addslashes() Versus mysql_real_escape_string()

magic_quotes_gpc is schijnveiligheid. Het staat tegenwoordig ook uit in de default ("This feature has been DEPRECATED and REMOVED as of PHP 6.0.0. Relying on this feature is highly discouraged.").

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • ? ?
  • Registratie: Mei 2007
  • Niet online

? ?

Eigenlijk zou Tweakers.net een uitgebreide sectie moeten hebben over SQL injection.
De basis van SQL injectie heb ik wel door, maar ik heb ergens gelezen dat je bv. ook de hexadecimale notering kunt gebruiken en dat de MYSQL interpreter deze dan omzet naar het gewenste karakter??

Zo ongeveer werd bv. de site RIAA.com gekraakt...

.php?id=9AF078E' + and+1=-1+union+select+1,2,3,4,concat_ws(0x3a,password,user),6,7,8,9+from+mysql.user+limit+0,1/*

Als je niet alles afweet hoe mysql werkt, is het moeilijk om je tegen alles te beschermen

[ Voor 27% gewijzigd door ? ? op 29-04-2008 11:25 ]


Acties:
  • 0 Henk 'm!

  • user109731
  • Registratie: Maart 2004
  • Niet online
era.zer schreef op dinsdag 29 april 2008 @ 11:15:
Zo ongeveer werd bv. de site RIAA.com gekraakt...

.php?id=9AF078E' + and+1=-1+union+select+1,2,3,4,concat_ws(0x3a,password,user),6,7,8,9+from+mysql.user+limit+0,1/*
Basic SQL injection, dat id-argument had nooit zo bij MySQL aan mogen komen. Dit heeft volgens mij weinig met hexadecimale notering te maken? Je verwacht een decimale integer en 9AF078E is dat niet, en al helemaal niet met die lading sql erachter :)
Als je niet alles afweet hoe mysql werkt, is het moeilijk om je tegen alles te beschermen
SQL injection is IMHO helemaal niet moeilijk te voorkomen. mysql_real_escape_string() voor strings, en typecasts voor integers etc. moet genoeg zijn. Je moet het alleen nergens vergeten, het handigste is daarom om dit centraal te doen, bijvoorbeeld een functie die automatisch de argumenten escaped, 'invult' in de query en de query uitvoert. Anders ga je geheid ergens de fout in. Dit en escapen tegen XSS-attacks en je zit redelijk safe :)

Van alle 'attacks' tegen een gemiddelde PHP-website is XSS denk ik nog de lastigste. De rest is veel common sense en altijd je input wantrouwen. Een include($eenGetVar.'.php') is gewoon dwaas.

[ Voor 14% gewijzigd door user109731 op 29-04-2008 12:57 ]


Acties:
  • 0 Henk 'm!

  • ? ?
  • Registratie: Mei 2007
  • Niet online

? ?

-foutief-

dat was niet goed NME, excuses

[ Voor 137% gewijzigd door ? ? op 29-04-2008 12:57 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Ook dat is weer niet relevant. Je hebt het over SQL injectie maar de functie htmlspecialchars die je aanhaalt heeft daar niets mee te maken. Bovendien is de aangegeven uitvoer van die functie helemaal niet dezelfde uitvoer die er direct onder staat, dus ik vraag me af of degene die dat gezegd heeft wel helemaal wakker was.

Daarnaast: als het wel addslashes/mysql_real_escape_string was geweest, dan was alles, zoals je zelf al laat zien, netjes geëscaped. Slashes worden verdubbeld en quotes krijgen ook een slash ervoor, precies wat je zou verwachten, en precies wat je zonder probleem in een MySQL query kan stoppen.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

Verwijderd

Gomez12 schreef op maandag 28 april 2008 @ 23:54:
[...]

Ok, nu $i=2.2371, wat is de uitkomst van deze oefening en wat staat er in de dbase? Oh wacht, ik mocht geen floats hieraan meegeven ok $i=2.24 dan? Oh, mag ik ook geen decimal(4,2) meegeven...
dit gaat er om als het veld in de db een INT is.. dus niet een decimal oid. en als je dan 2.2371 invult zal hij 2 opslaan. maar hij gaat er niet dood op. wil je checken of iets een decimal is voor je het er in propt zal je dat even van te voren moeten doen. maar als je moedwillig floats in je int probeert te stoppen is er al iets anders fout.
Gomez12 schreef op maandag 28 april 2008 @ 23:54:
Hmmm, ik zou ipv ip-check gewoon standaard alles ook mee laten lopen naar een error-log. Kan je ook nog iets met klanten die melden dat ze een uur geleden een fout kregen...
ik doe iig altijd alles naar errorlog. en criticals via mail. maar voor intern testen logt hij wel naar het scherm om debuggen te vereenvoudigen
Bosmonster schreef op dinsdag 29 april 2008 @ 10:37:
Waarom zou je eerst controleren als je iets cast in PHP? Cast gewoon naar dat wat het moet zijn (int, float, wat je verwacht). PHP gaat daar soepel mee om en converteert indien nodig.
zodra er in een veld die als int bedoeld is ineens iets heel anders gepropt wordt (een string oid) wil ik dan kunnen loggen. vandaar dat ik eigenlijk altijd een cast doe, maar ook een check er voor.

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Verwijderd schreef op dinsdag 29 april 2008 @ 19:23:
[...]
dit gaat er om als het veld in de db een INT is.. dus niet een decimal oid. en als je dan 2.2371 invult zal hij 2 opslaan. maar hij gaat er niet dood op. wil je checken of iets een decimal is voor je het er in propt zal je dat even van te voren moeten doen. maar als je moedwillig floats in je int probeert te stoppen is er al iets anders fout.
Jammer genoeg niet, door het niet goed van te voren te checken krijg je gewoon dat je dbase dingen anders kan opslaan dan dat je het aanlevert. Of dit moedwillig gebeurt dat wens ik te betwijfelen.

Maar imho hoort een dbase gewoon de data op te slaan die ik aanlever en niet stiekem dingen af te korten. Juist door dit soort geintjes van mysql/php check ik eerst meerdere keren alle waarden om er zeker van te zijn dat wat ik aanlever ook echt opgeslagen gaat worden ( let op dit zijn geen validatie checks, die zitten hiervoor, maar meer checks om te zien of de dbase het wel aankan ).

Heb het al een paar keer gezien dat een veldgrootte wel in de code werd veranderd maar niet in de dbase, kwam geen error, leek goed te gaan totdat je het eruit haalde en alles getruncated was...
Pagina: 1