[MySQL+PHP] mysqli::real_escape_string veilig genoeg?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • nickb90
  • Registratie: Mei 2007
  • Laatst online: 13-09 23:30
Beste,

Na mijn vorige probleem, waar ik erg goed geholpen ben (en er nog steeds mee bezig ben :P) had ik een andere vraag.

Als je in de nieuwe versie van MySQL (mysql improved) je gegevens wilt beveiligen om te voorkomen dat er foutieve code uitgevoerd word dan heb je de mysqli::real_escape_string.

Nu vroeg ik me dus af, ik heb hier ook een ander topic over gelezen hier vanuit 2008 en daar vonden ze het veilig genoeg. Maar nu vroeg ik me dus af, zijn er betere manieren? En ja, waarom dan?

Ik ben benieuwd.

Nick

[ Voor 9% gewijzigd door nickb90 op 17-01-2010 12:13 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Define "veilig genoeg". Het is sowieso belangrijk dat je het juist gebruikt (we zien het zooo vaak verkeerd gebruikt worden hier).
Wil je een andere (of het "beter" is laat ik in het midden, maar persoonlijk vind ik van wel) manier wil dan kun je eens kijken naar parameterized queries. Dan heb je al die flauwekul van escapen niet.

[ Voor 18% gewijzigd door RobIII op 17-01-2010 14:55 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Cyphax
  • Registratie: November 2000
  • Laatst online: 14:03

Cyphax

Moderator LNX
Maar nu vroeg ik me dus af, zijn er betere manieren? En ja, waarom dan?
Wat RobIII hierboven al schrijft: parameterized queries gebruiken. Dat is veiliger omdat je niet zo bang hoeft te zijn voor het goed escapen van je queries, je hebt minder te lijden onder encodingproblemen van strings, en er zijn andere parametertypen hebt naast strings waar je ook minder werk mee hebt op die manier. De parameters worden los van de query naar de server gestuurd die er zelf mee aan de slag gaat. Laat het gedeelte van afhandelen van de inhoud van de parameters dus mooi over aan de databaseserver.

[ Voor 6% gewijzigd door Cyphax op 17-01-2010 15:01 ]

Saved by the buoyancy of citrus


Acties:
  • 0 Henk 'm!

  • Aloys
  • Registratie: Juni 2005
  • Niet online
RobIII schreef op zondag 17 januari 2010 @ 14:54:
Define "veilig genoeg". Het is sowieso belangrijk dat je het juist gebruikt (we zien het zooo vaak verkeerd gebruikt worden hier).
Wil je een andere (of het "beter" is laat ik in het midden, maar persoonlijk vind ik van wel) manier wil dan kun je eens kijken naar parameterized queries. Dan heb je al die flauwekul van escapen niet.
In het stukje FAQ waar jij naar linkt staat expliciet vermeld dat het niet voor PHP/MySQL opgaat. In PHP is er namelijk ook geen manier om parameters toe te voegen aan je query (tenzij je een platform gebruikt). :)

Quote van de FAQ:
Dit stuk is niet van toepassing op de combinatie PHP/MySQL. Over hoe je SQL injection e.d. kan voorkomen lees je meer in de PHP FAQ over escapen in MySQL en beveiliging van websites.

[ Voor 12% gewijzigd door Aloys op 17-01-2010 15:07 . Reden: Stukje uit de FAQ ]


Acties:
  • 0 Henk 'm!

  • jeroenikke
  • Registratie: Augustus 2003
  • Laatst online: 13:04
Maar dat lukt wel als je PDO gebruikt in php. Dan kan je parameterized transactions uitvoeren.

EDIT:
hier meer info:
http://www.php.net/manual/en/pdo.prepared-statements.php
(dit is voor alle pdo drivers)

hier info over de mysql pdo driver:
http://php.net/manual/en/ref.pdo-mysql.php

[ Voor 51% gewijzigd door jeroenikke op 17-01-2010 15:15 ]


Acties:
  • 0 Henk 'm!

  • nickb90
  • Registratie: Mei 2007
  • Laatst online: 13-09 23:30
Ik ben misschien niet helemaal volledig geweest inderdaad in mijn openingspost, ik gebruik het inderdaad in combinatie met PHP 5. En zoals Aloys aangeeft is het voor dat niet mogelijk.

Echter had ik er nog nooit van gehoord en kan ik het misschien wel voor mijn schoolprojecten gebruiken (Ook MySQL zonder php o.i.d.).

Ik zal de openingspost aanpassen en een titel aanpassing vragen ;)

Mijn excuses voor de onduidelijkheid

Edit

@Jeroenikke, daar ga ik me is in verdiepen ;) even inlezen en testen! thanks :)

@derest, bedankt voor alle reactie's en weer een duidelijke uitleg ;)

[ Voor 16% gewijzigd door nickb90 op 17-01-2010 15:20 ]


Acties:
  • 0 Henk 'm!

  • Aloys
  • Registratie: Juni 2005
  • Niet online
jeroenikke schreef op zondag 17 januari 2010 @ 15:11:
Maar dat lukt wel als je PDO gebruikt in php. Dan kan je parameterized transactions uitvoeren.
Dat bedoelde ik met platform, maar dat moest natuurlijk framework zijn. Overigens ben ik wel benieuwd hoe je de real_escape_string functie verkeerd kan gebruiken?

Ik kom er overigens nooit mee in aanrakingen, want ik werk alleen met ID's van pagina's. Dus integer waarden:
PHP:
1
$iPaginaID = intval($_GET['page']);

Dat lijkt mij voor integer waarden een hele veilige manier?

Acties:
  • 0 Henk 'm!

  • MueR
  • Registratie: Januari 2004
  • Laatst online: 13:47

MueR

Admin Tweakers Discord

is niet lief

Aloys schreef op zondag 17 januari 2010 @ 15:18:
Dat bedoelde ik met platform, maar dat moest natuurlijk framework zijn. Overigens ben ik wel benieuwd hoe je de real_escape_string functie verkeerd kan gebruiken?
Zoiets bijvoorbeeld:
PHP:
1
2
3
4
// $_POST is onveilig, want dat is user input
foreach ($_POST as $key => $value)
  $_POST[$key] = mysqli_real_escape_string($value);
// Yay, nu is mn $_POST 'veilig' en kan ik het lomp in de DB rossen
Ik kom er overigens nooit mee in aanrakingen, want ik werk alleen met ID's van pagina's. Dus integer waarden:
PHP:
1
$iPaginaID = intval($_GET['page']);

Dat lijkt mij voor integer waarden een hele veilige manier?
Jij hebt nooit formulieren op je pagina die verzonden worden? Je werkt nooit met een admin waar iemand een pagina aanmaakt? Dan kom je er inderdaad nooit mee in aanraking. De intval() functie is best nuttig in dat geval.

Met dit stukje code neem ik even aan dat al je URLs ongeveer dit zijn: http://www.domein.nl/index.php?page=14. Dat is nou ook niet echt de meest ideale manier van werken. Zodra je human readable urls gaat gebruiken (domein.nl/bier/pizza/borrelnootjes.html) werk je plots met strings en zal je die dus wel op een goede manier in je query moeten stoppen.

Anyone who gets in between me and my morning coffee should be insecure.


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Aloys schreef op zondag 17 januari 2010 @ 15:05:
[...]

In het stukje FAQ waar jij naar linkt staat expliciet vermeld dat het niet voor PHP/MySQL opgaat. In PHP is er namelijk ook geen manier om parameters toe te voegen aan je query (tenzij je een platform gebruikt). :)
Dat stukje is dan outdated want het kan wel degelijk. Ook met MySQLi (waar dit topic over gaat).
MueR schreef op zondag 17 januari 2010 @ 16:40:
Met dit stukje code neem ik even aan dat al je URLs ongeveer dit zijn: http://www.domein.nl/index.php?page=14. Dat is nou ook niet echt de meest ideale manier van werken. Zodra je human readable urls gaat gebruiken (domein.nl/bier/pizza/borrelnootjes.html) werk je plots met strings en zal je die dus wel op een goede manier in je query moeten stoppen.
Hoewel ik dat persoonlijk de mooiste url's vind (ik gebruik ze zelf ook vaak) zal in de praktijk 9 v.d. 10 keer toch een ID in de url verstopt zitten. T.net doet het, Webwereld doet het, Nu.nl doet het en ga zo maar door. En nét dat ID is dan belangrijk in de url, de rest is "mooimakerij"; verander de tekst in de url en je krijgt nog steeds hetzelfde artikel. (Een voorbeeld van een ID-loos url is bijv. TheDailyWTF.com en niet nader te noemen sites van m'n koters :+ )

Point being: Of je nou schrijft:
http://www.domein.nl/inde...ge=14&title=Borrelnootjes of http://www.domein.nl/14/borrelnootjes.html
het is lood-om-oud-ijzer.

De ID-less variant die jij omschrijft (het intval komt dan inderdaad te vervallen) wordt zelden gebruikt vanwege de kans op duplicate keys. Het probleem met zo'n "natural" URL is dat je verdomdes goed moet oppassen of een key niet al eerder gebruikt is; in dat geval wil je een "webmaster" niet opzadelen met een "duplicate key blabla" fout en zul je 'm dus moeten dwingen een andere titel te gebruiken. Nu zul je bij "vijf gevolgen van de chinese google hack" niet zo snel tegen een duplicate key aan lopen, maar hier op T.net zou 't me niks verbazen als (ik roep maar wat) er binnen 2 jaar tijd een duplicate key ontstaat door (bijv.) "Samsung komt met nieuwe TV-serie".

Het kan wel, in de praktijk gebeurt het weinig.

[ Voor 81% gewijzigd door RobIII op 17-01-2010 21:01 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Aloys
  • Registratie: Juni 2005
  • Niet online
MueR schreef op zondag 17 januari 2010 @ 16:40:

Zoiets bijvoorbeeld:
PHP:
1
2
3
4
// $_POST is onveilig, want dat is user input
foreach ($_POST as $key => $value)
  $_POST[$key] = mysqli_real_escape_string($value);
// Yay, nu is mn $_POST 'veilig' en kan ik het lomp in de DB rossen
En dat is onveilig omdat je POST-vars niet kan aanpassen of niet de gehele array doorloopt?
Jij hebt nooit formulieren op je pagina die verzonden worden? Je werkt nooit met een admin waar iemand een pagina aanmaakt? Dan kom je er inderdaad nooit mee in aanraking. De intval() functie is best nuttig in dat geval.
Ik heb een contactformulier, die gaat rechtstreeks over de mail :P . Overigens heb ik wel een Admin-panel (waar ik de enige gebruiker ben), maar daar heb ik eigenlijk nooit gecheckt of ik het wel veilig geprogrammeerd heb. :$ (Ga het zo ff nakijken)
Met dit stukje code neem ik even aan dat al je URLs ongeveer dit zijn: http://www.domein.nl/index.php?page=14. Dat is nou ook niet echt de meest ideale manier van werken. Zodra je human readable urls gaat gebruiken (domein.nl/bier/pizza/borrelnootjes.html) werk je plots met strings en zal je die dus wel op een goede manier in je query moeten stoppen.
Zoals je collega hierboven al zegt: Bij dynamische sites zul je altijd een unieke key moeten hebben. Het meest logisch is dan een ID. Overigens staat http://www.website.nl/*ID*/eventueel_een_nutteloze_naam
wel netter. :)

Acties:
  • 0 Henk 'm!

  • MueR
  • Registratie: Januari 2004
  • Laatst online: 13:47

MueR

Admin Tweakers Discord

is niet lief

Aloys schreef op zondag 17 januari 2010 @ 21:20:
En dat is onveilig omdat je POST-vars niet kan aanpassen of niet de gehele array doorloopt?
Meer omdat je nog steeds totaal niet weet wat je nou eigenlijk je database in frot, laat staan of het uberhaupt nuttig is.
Zoals je collega hierboven al zegt: Bij dynamische sites zul je altijd een unieke key moeten hebben. Het meest logisch is dan een ID. Overigens staat http://www.website.nl/*ID*/eventueel_een_nutteloze_naam
wel netter. :)
En dan krijg je een klant die perse een pagina structuur wil die ik al eerder aanhaalde, met nesting. Dan zul je toch alles moeten controleren ;)

Anyone who gets in between me and my morning coffee should be insecure.


Acties:
  • 0 Henk 'm!

  • Aloys
  • Registratie: Juni 2005
  • Niet online
MueR schreef op zondag 17 januari 2010 @ 21:26:
Meer omdat je nog steeds totaal niet weet wat je nou eigenlijk je database in frot, laat staan of het uberhaupt nuttig is.
Maar je zet toch sowieso nooit zomaar je post-vars in de database. Je gebruikt alleen de relevante keys. Het enige wat ik kan bedenken is dat het lelijk is en vaak ook overbodig.
En dan krijg je een klant die perse een pagina structuur wil die ik al eerder aanhaalde, met nesting. Dan zul je toch alles moeten controleren ;)
Ik heb geen klanten, maar in dat geval zou ik het ook zeker moeten uitzoeken. Het is ook niet dat ik het uit principe niet toepas, maar ik heb simpelweg de noodzaak daartoe nog niet gehad.
RobIII schreef op zondag 17 januari 2010 @ 20:33:
[...]

Dat stukje is dan outdated want het kan wel degelijk. Ook met MySQLi (waar dit topic over gaat).

[...]
Dat ziet er goed uit, binnenkort maar eens een beetje mee spelen.

Overigens heb ik eens gekeken naar mijn eigen beveiliging. Ik check de data vanuit mijn adminpanel dus niet met mysql_real_escape_string (Oeps), maar je moet eerst in het adminpanel zien te komen. Bij het aanmelden wordt de volgende code aangeroepen:
PHP:
1
2
3
    //Login
    $Login_Handle->Login(mysql_real_escape_string((string) $_POST['username']), 
                            mysql_real_escape_string((string) $_POST['password']));
_/-\o_ O-)
Voel ik me toch wel een beetje een genie dat ik dat wel weer heb afgevangen. :+

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Maar het staat dan niet op de logische plek. Tijdens het schrijven van de aanroep heb je geen ene fuck met mysql of wat dan ook te maken. Dat hoort dus in login of zelfs nog dieper weggestopt, iig ergens bij code die iets met de db van doen heeft.

[ Voor 12% gewijzigd door Voutloos op 17-01-2010 21:40 ]

{signature}


Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Aloys schreef op zondag 17 januari 2010 @ 21:20:

[...]

Ik heb een contactformulier, die gaat rechtstreeks over de mail :P . Overigens heb ik wel een Admin-panel (waar ik de enige gebruiker ben), maar daar heb ik eigenlijk nooit gecheckt of ik het wel veilig geprogrammeerd heb. :$ (Ga het zo ff nakijken)
Dan moet je toch controleren op injections in je email-header, in je bericht, enz... Ook zomaar iets mailen is niet veilig.

Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Aloys schreef op zondag 17 januari 2010 @ 21:36:

[...]

Dat ziet er goed uit, binnenkort maar eens een beetje mee spelen.

Overigens heb ik eens gekeken naar mijn eigen beveiliging. Ik check de data vanuit mijn adminpanel dus niet met mysql_real_escape_string (Oeps), maar je moet eerst in het adminpanel zien te komen. Bij het aanmelden wordt de volgende code aangeroepen:
PHP:
1
2
3
    //Login
    $Login_Handle->Login(mysql_real_escape_string((string) $_POST['username']), 
                            mysql_real_escape_string((string) $_POST['password']));
_/-\o_ O-)
Voel ik me toch wel een beetje een genie dat ik dat wel weer heb afgevangen. :+
Dat is ook niet goed.

Je moet de data pas escapen op het moment dat je de query maakt/uitvoert. Nu geef je ge-escapte data mee aan die Login() functie, dat is niet juist. Het escapen moet gebeuren in de Login() functie.

Als iemand nu een ' in zijn wachtwoord heeft, die jij hebt gehashed. Dan kan het zijn dat je op ene plek een ' hashed en daarna escaped, en op de andere plek eerst escapen en daarna dus een \' hashed.

Acties:
  • 0 Henk 'm!

  • Aloys
  • Registratie: Juni 2005
  • Niet online
Voutloos schreef op zondag 17 januari 2010 @ 21:39:
Maar het staat dan niet op de logische plek. Tijdens het schrijven van de aanroep heb je geen ene fuck met mysql of wat dan ook te maken. Dat hoort dus in login of zelfs nog dieper weggestopt, iig ergens bij code die iets met de db van doen heeft.
Klopt, dat is eigenlijk verkeerd. Ik zal het wel even gaan veranderen. :)
HuHu schreef op zondag 17 januari 2010 @ 21:40:
[...]

Dan moet je toch controleren op injections in je email-header, in je bericht, enz... Ook zomaar iets mailen is niet veilig.
Tja, daar heb ik eigenlijk nog niet over nagedacht. Gelukkig worden de mails als plain-text verstuurd. :)

Overigens heb ik het idee dat ik het topic kaap ofzo :+ (Vind het gewoon een leuke, interessante en nuttige discussie :) )

EDIT: Overigens ben ik toch stom bezig geweest. De Login-functie voert zelf ook de mysql_real_escape_string uit op de variabelen die ik erin stop. :P

[ Voor 7% gewijzigd door Aloys op 17-01-2010 21:46 ]


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Aloys schreef op zondag 17 januari 2010 @ 21:44:
Tja, daar heb ik eigenlijk nog niet over nagedacht. Gelukkig worden de mails als plain-text verstuurd. :)
Denk er maar over na dan (of open een topic) want als je er zo simpel over denkt heb je toch wel een behoorlijke kans op een fuck up. :>

{signature}


Acties:
  • 0 Henk 'm!

  • cariolive23
  • Registratie: Januari 2007
  • Laatst online: 18-10-2024
Het gebruik van prepared statements heeft de voorkeur, al zitten daar met MySQLi nog wel wat haken en ogen aan. Ook het resultaat van een query moet je met MySQLi ineens anders gaan behandelen, zie http://nl.php.net/manual/en/mysqli.prepare.php, zie bind_result(), wat dus weer extra tijd / werk kost.

De combinatie PHP / PostgreSQL werkt dan een heel stuk handiger, PHP heeft veel mooiere/eenvoudiger functies voor het gebruik van PostgreSQL dan voor het gebruik van MySQL, zie bv. pg_query_params() (query en z'n parameters 1x uitvoeren) of pg_prepare() / pg_execute() (1x preparen en meerdere keren met verschillende parameters uitvoeren). Je hoeft geen aparte code te schrijven voor het verwerken van de resultaten, gooi het resultaat in een variabele en klaar ben je.
Pagina: 1