[PHP] Integers en Nullen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
Ik zit met een probleem.

Ik heb een url met een id erin die elke 24 uur maar 1x aangeklikt mag worden, dit werkt prima.
Maar als men deze url kopieert en voor het cijfer een 0 plaatsen word dit ook goed gerekend en krijgt deze user er credits over, wat dus niet de bedoeling is.

Voorbeeld:
http://www.bla.com/laatzien.php?id=5 <-- deze word dan op de site doorgestreept als een timer is afgelopen.

Daarna pakken kwaadwilligen die link weer en maken er dit van:
http://www.bla.com/laatzien.php?id=05
http://www.bla.com/laatzien.php?id=005
Dit word dan gewoon goed gerekend, wat dus niet mag.

Ik zie dit na de hand prima in de database terug komen, maar brengt zoveel werk met zich mee en ik zoek er dus ene oplossing voor.

Dat id komt uit een database en word opgeslagen als integer en is ingesteld als auto_increment. Aangezien er meerdere van dit soort links zijn en ook bij komen.

Ik zat te denken aan een functie is als (voorbeeld is wat slordig etc, maar gaat om het idee:
code:
1
2
3
4
5
6
7
8
if ?id=0x (dus als er eerst een 0 voor een cijfer staat)
{
  then: geef error
}
else
{
  laat: zien
}


Alleen ik heb geen idee hoe ik dit moet aanpakken aangezien dit in de url balk gebeurd.

Of ik pak het aan bij het in de database stoppen, want daarin zie ik de variable voorbij komen, alleen hoe pak ik dit precies aan want hij zet dan alleen: 05/005/0005 etc in de database.

Iemand die mij hiermee kan helpen?

Acties:
  • 0 Henk 'm!

  • TheDane
  • Registratie: Oktober 2000
  • Laatst online: 22:34

TheDane

1.618

Er zijn diverse manieren.

Ik gebruik intval() om van een string een getal (integer) te maken. Daar staan dan geen nullen meer voor. De uitkomst van intval() kun je dus gebruiken om te checken of een waarde al gebruikt is in de afgelopen 24u

[ Voor 11% gewijzigd door TheDane op 27-08-2008 20:25 . Reden: linkje toegevoegd ]


Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
id=id * 1

Of gewoon handmatig casten naar een int.

Nu heb je gewoon geen controle op je input. Verwacht je alleen ints maak er dan ook ints van, een int heeft geen voorloopnullen. En doe dit aub niet met stringfuncties...

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Gomez12 schreef op woensdag 27 augustus 2008 @ 20:26:
id=id * 1

Of gewoon handmatig casten naar een int.

Nu heb je gewoon geen controle op je input. Verwacht je alleen ints maak er dan ook ints van, een int heeft geen voorloopnullen. En doe dit aub niet met stringfuncties...
"handmatig" casten 8)7

Cast gewoon naar een integer zoals het hoort:
PHP:
1
$int = (int) $string;
Let wel op dat je met je id's niet boven de 2147483647 komt, ivm overflow ;)

Acties:
  • 0 Henk 'm!

  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
TheDane schreef op woensdag 27 augustus 2008 @ 20:25:
Er zijn diverse manieren.

Ik gebruik intval() om van een string een getal (integer) te maken. Daar staan dan geen nullen meer voor. De uitkomst van intval() kun je dus gebruiken om te checken of een waarde al gebruikt is in de afgelopen 24u
Er word al gecontroleerd of die al gebruik is de afgelopen 24u dus daar hoef ik niks mee te doen.

Ik moet er puur voor zorgen dat als er mensen in de url na ?id= en voor het cijfer, een 0 of meerdere nullen staan dat er dan nadat de timer is afgelopen.
Of niks gebeurt dus het inserten in de database, en dus worden de gegevens van die gebruiker niet bij gewerkt.
Of dat ze al bij het bijwerken van de url dus een 0 of meerdere voor het cijfer, en als ze dan op enter drukken dat die pagina laat dat er een error te voorschijn komt.

Ook zeg je dat je dat wat je aangeeft de intval functie gebruikt om van een string een integer te maken, maar tenminste zo denk ik dat het cijfer wat daar staat al een integer is. Want die hele url code ervoor word namelijk niks mee gedaan in de database, het gaat puur om het nummer wat bij een id hoort.
En dit id nummer komt ook uit een database en dat veld is al een integer.

[ Voor 15% gewijzigd door FabiandJ op 27-08-2008 22:27 ]


Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
http parameters zijn altijd strings bij het importeren, ongeacht waar het vandaan komt.
05 is geen int, 5 wel. Bij ints ( in het decimale stelsel ) kan je geen voorloopnullen hebben omdat ze niet relevant zijn.
Bij strings kan je zo ongeveer alles hebben omdat het om de letterlijke interpretatie gaat.

Een cijfer an sich zegt niets over het type, een 0 of een 1 kan een boolean zijn, een string, een int, een float, een double etc.etc. Zonder een type-aanduiding zegt het niets. GET-parameters kennen geen type-aanduidingen dus wordt het meest algemene standaard gepakt ( string ) en moet je het zelf casten naar het type wat je verwacht.

Vb. de tekst : 1 peer. is een string, is het 1e karakter hiervan ( de 1 ) nu opeens een int? nee, het is nog steeds een steeds een string alleen valt hij te casten naar een int. Voor het casten is het een string, na het casten is het een int.

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Ik snap er niks van. Post eens wat code, en leer normaal schrijven. :P

Acties:
  • 0 Henk 'm!

Verwijderd

Zoijar schreef op woensdag 27 augustus 2008 @ 22:58:
Ik snap er niks van. Post eens wat code, en leer normaal schrijven. :P
Wat vriendelijker zou wel mogen?

PHP:
1
2
3
4
5
6
7
// ?a=1 peer
echo $_GET['a']; // "1 peer", string
echo (int)$_GET['a']; // "1", int

// ?a=0005
echo $_GET['a']; // "0005", string
echo (int)$_GET['a']; // "5", int


Easy toch?

Acties:
  • 0 Henk 'm!

  • Alain
  • Registratie: Oktober 2002
  • Niet online
Gomez12 schreef op woensdag 27 augustus 2008 @ 22:54:
05 is geen int, 5 wel. Bij ints ( in het decimale stelsel ) kan je geen voorloopnullen hebben omdat ze niet relevant zijn.
Ongeacht welk stelsel mogen voorloopnullen altijd, juist omdat ze niet relevant zijn. ;)

You don't have to be crazy to do this job, but it helps ....


Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
AlainS schreef op woensdag 27 augustus 2008 @ 23:31:
[...]


Ongeacht welk stelsel mogen voorloopnullen altijd, juist omdat ze niet relevant zijn. ;)
You say potato, i say potato, oftewel definitiefout van mij :)

Maar er staat me iets van bij dat voorloopnullen in php-variabelen zo af en toe wel eens behandeld werden als cijfers in het 8-tallige stelsel ( uit mijn hoofd vanwege het automatische casten )?
Iemand die kan vertellen of ik hier helemaal compleet verkeerd mee zit?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

Octale notatie geldt alleen voor literals in code. Niet bij het casten van een string naar een int. Net als bij de 0x prefix voor hexadecimaal :). Eh nee, bij een 0x in een string interpreteert ie dat weer wél als hexadecimaal 8)7

[ Voor 24% gewijzigd door .oisyn op 28-08-2008 00:13 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • user109731
  • Registratie: Maart 2004
  • Niet online
Gomez12 schreef op woensdag 27 augustus 2008 @ 23:57:
[...]
Maar er staat me iets van bij dat voorloopnullen in php-variabelen zo af en toe wel eens behandeld werden als cijfers in het 8-tallige stelsel ( uit mijn hoofd vanwege het automatische casten )?
Iemand die kan vertellen of ik hier helemaal compleet verkeerd mee zit?
Van PHP: Integers:
PHP:
1
2
3
4
$a = 1234; // decimal number
$a = -123; // a negative number
$a = 0123; // octal number (equivalent to 83 decimal)
$a = 0x1A; // hexadecimal number (equivalent to 26 decimal)

Volgens mij is dit iets wat de parser/tokenizer herkent en omzet. Het werkt dus enkel als je het letterlijk zo in de code hebt staan, intval('05'); zal dus gewoon 5 opleveren :)

  • --MeAngry--
  • Registratie: September 2002
  • Laatst online: 19-09 16:35

--MeAngry--

aka Qonstrukt

Klopt, 0777 is iets anders dan 777 in PHP. :) 0777 wordt automatisch als octaal getaal gezien. Dus let op:

"0777" == 777 => true
0777 == 777 => false

De wondere wereld van PHP :P

Tesla Model Y RWD (2024)


  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

--MeAngry-- schreef op donderdag 28 augustus 2008 @ 00:06:
Klopt, 0777 is iets anders dan 777 in PHP. :) 0777 wordt automatisch als octaal getaal gezien. Dus let op:

"0777" == 777 => true
0777 == 777 => false

De wondere wereld van PHP :P
Dat is (zoals het hoort) in beide gevallen gewoon false ;)

  • remmelt
  • Registratie: Januari 2001
  • Laatst online: 09-04 12:25
Je doet (waarschijnlijk) geen inputvalidatie. Je wil een int zien in je db, maar er komt een string in je sql statement terecht. Nooit, maar dan ook nooit, mag je invoer van een gebruiker vertrouwen, vooral niet op het web.
Maak gebruik van prepared statements, bijvoorbeeld via PDO. Dit zit tegenwoordig in PHP ingebakken en is db-onafhankelijk te gebruiken. Leer hoe het werkt en doe er je voordeel mee. Overigens staat dit los van de inputvalidatie, die moet je ook doen. Bij een prepared statement doe je bijvoorbeeld:

UPDATE table WHERE id = :id AND datum != vandaag

PDO vervangt dan de :id voor je id. Zie ook http://nl.php.net/manual/en/pdo.prepared-statements.php

[ Voor 6% gewijzigd door remmelt op 28-08-2008 00:12 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

De wondere wereld van PHP? Dat is in vrij veel talen zo, hoor...
Erkens schreef op donderdag 28 augustus 2008 @ 00:09:
[...]

Dat is (zoals het hoort) in beide gevallen gewoon false ;)
Niet in mijn PHP (4.nogwat). Voor hex gaat het idd op. Voor octaal niet.

[ Voor 69% gewijzigd door .oisyn op 28-08-2008 00:12 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • mocean
  • Registratie: November 2000
  • Laatst online: 04-09 10:34
Ik denk dat het probleem zoals omschreven "een url met een id erin die elke 24 uur maar 1x aangeklikt mag worden" op een heel andere manier zou moeten worden opgelost. Tuurlijk moet je de input valideren, zorgen dat het ook een INT is etc.
Maar je kan toch prima in de database opslaan/checken of er al een call is geweest naar dit id, en als er dan nog een komt, deze negeren?

Koop of verkoop je webshop: ecquisition.com


  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
@mocean : Dat probeert hij ook, maar doordat hij zijn input niet valideert, ziet hij 2 verschillende calls verschijnen ( 5 en 05 ). Waarschijnlijk zit zijn controle dan ook niet in de db maar in de php-laag.

  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
Verwijderd schreef op woensdag 27 augustus 2008 @ 23:29:
[...]

Wat vriendelijker zou wel mogen?

PHP:
1
2
3
4
5
6
7
// ?a=1 peer
echo $_GET['a']; // "1 peer", string
echo (int)$_GET['a']; // "1", int

// ?a=0005
echo $_GET['a']; // "0005", string
echo (int)$_GET['a']; // "5", int

Easy toch?
Jou voorbeeld gaat nu uit van dat als er iemand 0005 in de url gezet heeft dat die er 5 van maakt.
Maar moet het niet zijn van:
PHP:
1
2
3
// ?a=0005
$_GET['a'];
echo "dit mag niet";

Want alleen getallen zoals ?a=5 of ?a=6 mogen doorgaan, zolang er een 0 voor staat is het fout.

Ik laat hier maar even de code zien van hoe het precies in zijn werkt gaat, misschien verduidelijk dit het wat meer.

Zo komen eerst op deze pagina aan, nadat men zich heeft ingelogd:
Stap 1
In deze pagina word dit stuk code geladen:
Stap 2

Daarna klikken ze op een link en word dit op een nieuwe pagina geopend:
Stap 3
Zijn de 30 seconden om, zal dit uitgevoerd worden.
Stap 4

Ga je dan weer terug naar Stap 1 zal door je net bekeken link een streep staan.

Nu is dus het zo dat als je bij Stap 3 bijvoorbeeld een link hebt die je bekijkt met id=5 dat je na 30 seconden deze niet meer aan kan klikken.
Maar nou zit er een bug in het script dat als je van id=5 nou id=05 maakt dat dan diezelfde link word geopend en je dus na 30 seconden daar dus credits van krijgt die je dus niet hoort te krijgen enz.
Zo krijgen dus members die dit weten credits die ze niet verdienen.

En hoe kan ik dit dan dus tegen gaan, ik hoop dat het nu met de code er bij duidelijker is.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dutch3men schreef op donderdag 28 augustus 2008 @ 01:38:
[...]

Jou voorbeeld gaat nu uit van dat als er iemand 0005 in de url gezet heeft dat die er 5 van maakt.
Nee, wat iedereen in deze topic jou wijs probeert te maken is dat jij de input naar een int moet casten zodat het niet uitmaakt of het 0005 of 5 is. De hele issue is nou juist dat je strings loopt te vergelijken, terwijl je eigenlijk nummers wilt vergelijken.

[ Voor 13% gewijzigd door .oisyn op 28-08-2008 01:52 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

/me mooi gesproken .oisyn
PHP:
1
2
$lolz=$_COOKIE["usNick"];
$sqlr = "SELECT * FROM tb_users WHERE username='$lolz'";


Lichtjes offtopique, maar zeker een aandachtspunt!

usNick veranderen naar iets als... ' OR id = '1, dan krijg je de volgende query:
SQL:
1
SELECT * FROM tb_users WHERE username='' OR id = '1'

Is maar voorbeeldje, kan heel veel (evil) dingen mee. }:O

Zie dit:
Wikipedia: SQL-injectie

s6 ermee! :D

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

.oisyn schreef op donderdag 28 augustus 2008 @ 00:11:
Niet in mijn PHP (4.nogwat). Voor hex gaat het idd op. Voor octaal niet.
Ten eerste is PHP 4 gebruiken natuurlijk niet slim, want ten eerste is dat gewoon antiek en ten tweede niet meer ondersteund.
Verder had --MeAngry-- eerst die quotes daar niet staan, die heeft hij erbij geedit op het moment dat ik het even ging testen ;)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik "gebruik" sowieso geen PHP, dus your point is moot :Y)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

.oisyn schreef op donderdag 28 augustus 2008 @ 11:01:
Ik "gebruik" sowieso geen PHP, dus your point is moot :Y)
offtopic:
Maar je hebt het wel voor een testje gebruikt om tot jouw conclusie te komen ;)

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Ik reageerde op de TS, niet op jouw post.

"Ja, ik heb een id en die stop ik een keer in de 24 uur in de database, maar dan als het id 05 is doet hij het niet." "Oh ja, aha. Nou, dan zou ik het in de code aanpassen met een functie, zodat hij het wel doet..."

  • P.O. Box
  • Registratie: Augustus 2005
  • Niet online
TS:
je zegt dat gebruikers credits verdienen door die links aan te klikken. Verder zeg je:
at id komt uit een database en word opgeslagen als integer en is ingesteld als auto_increment. Aangezien er meerdere van dit soort links zijn en ook bij komen.
M.a.w. gebruikers kunnen eenvoudig id's raden.

Blijkbaar misbruiken gebruikers de URL om credits te scoren. Hoe moeilijk denk je dat het is om een scriptje te schrijven dat iedere dag even alle id's afgaat tot het maximum id? Denk dat je sowieso beter een ander type ID's kunt gaan gebruiken en dan ben je ook gelijk van je 0-en probleem af...

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Edwardvb schreef op donderdag 28 augustus 2008 @ 12:07:
en dan ben je ook gelijk van je 0-en probleem af...
Nee, met adequate user input validatie kom je van foute input problemen af. Input validatie is nu gewoon blijkbaar totaal afwezig, dus kans bestaat dat het msbruiken van dat id om credits te scoren nog wel het minst serieuze probleem is (sql injection etc).

{signature}


  • P.O. Box
  • Registratie: Augustus 2005
  • Niet online
? ik zeg het ook niet als oplossing voor z'n input validatie probleem... in mijn voorbeeld is het slechts een bij-effect, dat je van het 0-en probleem afbent... dat er nog veel meer problemen zullen zijn lijkt me zeer aannemelijk, gezien de reeds gemaakte fouten.... maar daar wilde ik nou niet ook nog eens op ingaan, dat zoekt TS verder zelf maar uit.. .en als TS daar niet uitkomt opent hij maar een nieuwe topic :)

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Ja, dat begreep ik wel. Maar dat leuke bijeffect is er enkel als je dan wel de input goed behandeld. ;) Oftewel: het echte probleem is en blijft gewoon dat regel numero uno mbt user input niet gevolgd wordt.

{signature}


  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
Verwijderd schreef op donderdag 28 augustus 2008 @ 02:17:
/me mooi gesproken .oisyn


[...]


PHP:
1
2
$lolz=$_COOKIE["usNick"];
$sqlr = "SELECT * FROM tb_users WHERE username='$lolz'";


Lichtjes offtopique, maar zeker een aandachtspunt!

usNick veranderen naar iets als... ' OR id = '1, dan krijg je de volgende query:
SQL:
1
SELECT * FROM tb_users WHERE username='' OR id = '1'

Is maar voorbeeldje, kan heel veel (evil) dingen mee. }:O

Zie dit:
Wikipedia: SQL-injectie

s6 ermee! :D
Bedankt voor het waarschuwen hiervoor, ik heb me namelijk hier nooit in verdiept om eerlijk te zijn.
Ik heb nu van dit stuk:
SQL:
1
2
$checkip = mysql_query("SELECT ip FROM tb_banned WHERE ip='$laip' OR lastiplog='$laip'");
$ip_exist = mysql_num_rows($checkip);


Dit gemaakt:
SQL:
1
2
$checkip = mysql_query("SELECT ip FROM tb_banned WHERE ip=' . addslashes($laip) . ' OR lastiplog=' . addslashes($laip) . '");
$ip_exist = mysql_num_rows($checkip);


Heb ik hier dan, voor dit stukje de SQL-injectie geblockt?

Ik ga eerst de SQL-injectie etc tegen voordat ik verder ga met het probleem waarvoor ik dit topic eigenlijk geopend had.
Ik heb dit gedaan aan de hand van dit voorbeeld klik

[ Voor 5% gewijzigd door FabiandJ op 28-08-2008 14:12 ]


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 21-09 02:21

Janoz

Moderator Devschuur®

!litemod

Waar haal je die $laip vandaan? Als je die gewoon uit REMOTE_ADRESS haalt lijkt het me een beetje nutteloos om een betrouwbare waarde waarvan het formaat ook bekend is te gaan escapen....

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee, je moet mysql_real_escape_string() gebruiken.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

Dutch3men schreef op donderdag 28 augustus 2008 @ 14:10:
Dit gemaakt:
SQL:
1
2
$checkip = mysql_query("SELECT ip FROM tb_banned WHERE ip=' . addslashes($laip) . ' OR lastiplog=' . addslashes($laip) . '");
$ip_exist = mysql_num_rows($checkip);


Heb ik hier dan, voor dit stukje de SQL-injectie geblockt?
Doe het dan zo:
PHP:
1
$checkip = mysql_query("SELECT ip FROM tb_banned WHERE ip='" . mysql_real_escape_string($laip) . "' OR lastiplog='" . mysql_real_escape_string($laip) ."'");
Janoz schreef op donderdag 28 augustus 2008 @ 14:13:
Waar haal je die $laip vandaan? Als je die gewoon uit REMOTE_ADRESS haalt lijkt het me een beetje nutteloos om een betrouwbare waarde waarvan het formaat ook bekend is te gaan escapen....
Als je 100% zeker weet dat het betrouwbaar is natuurlijk. Zelf escape ik het wel, die paar ms die de cpu daarmee bezig is vind ik niet boeiend ;)

  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
Janoz schreef op donderdag 28 augustus 2008 @ 14:13:
Waar haal je die $laip vandaan? Als je die gewoon uit REMOTE_ADRESS haalt lijkt het me een beetje nutteloos om een betrouwbare waarde waarvan het formaat ook bekend is te gaan escapen....
Die $laip haal ik hier uit vandaan.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    require('bancheck.php');

    $laip = getRealIP();
    if($laip!="127.0.0.1")
    {
        require('config.php');

        $checkip = mysql_query("SELECT ip FROM tb_banned WHERE ip=' . addslashes($laip) . ' OR lastiplog=' . addslashes($laip) . '");
        $ip_exist = mysql_num_rows($checkip);
    }
    if ($ip_exist>0) {
        echo "<center><h1>Error: You are banned!</h1></center>";
    } else { 
        echo "ga door";
    }


En dit is bancheck.php

  • Johnny
  • Registratie: December 2001
  • Laatst online: 14:39

Johnny

ondergewaardeerde internetguru

Eigenlijk moet je IP's omzetten naar integers met ip2long() omdat het gewoon 32-bit getallen zijn die op een bepalde manier worden weergegeven als strings zodat ze makkelijker leesbaar zijn. Dan hoef je ze daarna ook niet meer te escapen en is het ook nog eens 4 keer kleiner bij het opslaan.

Aan de inhoud van de bovenstaande tekst kunnen geen rechten worden ontleend, tenzij dit expliciet in dit bericht is verwoord.


  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
Even een klein vraagje wat betreft de SQL-injection.
Als ik bijvoorbeeld deze query heb:
SQL:
1
$query = "UPDATE tb_users SET password='$password', ip='$laip', email='$email', pemail='$pemail', country='$country' WHERE username='$trok'";


Moet ik dan alleen bij het where gedeelte het mysql_real_escape_string bij zetten of ook bij de rest?
Voordat ik straks erg veel moet veranderen :p
Of kan het geen kwaad, als ik het bij alles waar in een SQL query: $iets ,staat er de mysql_real_escape_string deel omheen bouw?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

Waarom het om gaat is dat als je een variabele hebt met een ' (of eventuele andere data die door MySQL als speciaal wordt behandeld) erin, je query niet meer klopt omdat die variabele letterlijk in de query string geplaatst wordt. Het is dus ook verstandig om het te doen voor elke variabele die je in de query string stopt. Dus overal waar $iets staat, zoals je zelf al zegt.

Dit geldt natuurlijk voor strings. Een int kan bijvoorbeeld geen ' bevatten, en daarom is het ook handig om die dingen die een int moeten zijn ook gewoon te casten naar int en ze niet als string te houden. Ben je meteen van je 0005 probleem af.

[ Voor 34% gewijzigd door .oisyn op 28-08-2008 15:41 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
Woei het 0005 probleem is opgelost :)
Bleek makkelijker te zijn dan ik dacht :X

Helemaal bovenin de code stond dit:
PHP:
1
$ads=limpiar($_GET["ad"]);


En daar heb ik nu dit van gemaakt:
PHP:
1
2
$adse=limpiar($_GET["ad"]);
$ads= (int) $adse;


De mensen kunnen nu nog wel in de url na het id?= een 0 invullen voor het cijfer, maar als de timer om is komt er gewoon een kruis te staan :)
Tevens heb ik overal nu ook de mysql_real_escape_string erin gezet.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dutch3men schreef op donderdag 28 augustus 2008 @ 19:17:
Woei het 0005 probleem is opgelost :)
Bleek makkelijker te zijn dan ik dacht :X
Idd. Want het enige wat je hoefde te doen was te luisteren naar wat hier gezegd werd 8)7

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • remmelt
  • Registratie: Januari 2001
  • Laatst online: 09-04 12:25
Dutch3men schreef op donderdag 28 augustus 2008 @ 15:28:
Even een klein vraagje wat betreft de SQL-injection.
Lees mijn post. Als je sql-injectie wilt tegengaan, is een gezonde eerste stap om gebruik te gaan maken van PDO en met name prepared statements. Is helemaal niet moeilijk, je moet even zien hoe het werkt en dat is het. Je bent dan ook meteen database-onafhankelijk. Je loopt nu te kutten met mysql_escape_string, dat kan veel gemakkelijker. Ik kan me niet meer herinneren dat ik direct mysql_*/pgsql_* functies heb aangeroepen in de laatste 5 jaar, en in die tijd heb ik heel veel PHP geprogrammeerd.

http://nl3.php.net/manual/en/pdo.prepared-statements.php

Acties:
  • 0 Henk 'm!

  • P.O. Box
  • Registratie: Augustus 2005
  • Niet online
en lees ook nog even mijn post voor overige stappen...
of , als die credits nog iets opleveren, geef mij het adres van je site ;)

Acties:
  • 0 Henk 'm!

  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
remmelt schreef op donderdag 28 augustus 2008 @ 23:11:
[...]


Lees mijn post. Als je sql-injectie wilt tegengaan, is een gezonde eerste stap om gebruik te gaan maken van PDO en met name prepared statements. Is helemaal niet moeilijk, je moet even zien hoe het werkt en dat is het. Je bent dan ook meteen database-onafhankelijk. Je loopt nu te kutten met mysql_escape_string, dat kan veel gemakkelijker. Ik kan me niet meer herinneren dat ik direct mysql_*/pgsql_* functies heb aangeroepen in de laatste 5 jaar, en in die tijd heb ik heel veel PHP geprogrammeerd.

http://nl3.php.net/manual/en/pdo.prepared-statements.php
Maar de functie mysql_escape_string houd toch ook de SQL-injectie tegen, anders snap ik er niks meer van :? ?
Voor zover ik kan opmaken uit de code en dus de verschillen zie ik dat je bij "mysql_escape_string" functie direct verbinding hebt met je database.
Bij PDO word eerst alle opgebouwd, en als die klaar is word er pas verbinding gemaakt met de database en uitgevoerd, toch?

En wat me nog niet helemaal helder is, is dit namelijk: mysql_real_escape_string gaat uit van een string neem ik aan.
Wat doe ik dan bijvoorbeeld met dit stukje en dan voornamelijk het id stukje aangezien dit een integer is die ik net heb omgezet naar een integer.
PHP:
1
$sql = "SELECT * FROM tb_ad WHERE id=$ad'";

Of mag ik daar ook gewoon mysql_real_escape_string bij zetten, al lijkt mij dan dat ik er gewoon weer een string van maak.
Edwardvb schreef op vrijdag 29 augustus 2008 @ 00:54:
en lees ook nog even mijn post voor overige stappen...
of , als die credits nog iets opleveren, geef mij het adres van je site ;)
Ja dat is er, help maar mee dan krijg je het :P.

Acties:
  • 0 Henk 'm!

  • Johnny
  • Registratie: December 2001
  • Laatst online: 14:39

Johnny

ondergewaardeerde internetguru

Dutch3men schreef op vrijdag 29 augustus 2008 @ 01:17:
[...]

Maar de functie mysql_escape_string houd toch ook de SQL-injectie tegen, anders snap ik er niks meer van :? ?
Voor zover ik kan opmaken uit de code en dus de verschillen zie ik dat je bij "mysql_escape_string" functie direct verbinding hebt met je database.
Bij PDO word eerst alle opgebouwd, en als die klaar is word er pas verbinding gemaakt met de database en uitgevoerd, toch?

En wat me nog niet helemaal helder is, is dit namelijk: mysql_real_escape_string gaat uit van een string neem ik aan.
Je query wordt als een string naar de database verstuurd, dus alle gegevens die je daar in verwerkt zijn ook een string daar in.

Voor integers kun je echter beter een functie zoals intval() gebruiken, dan weet je zeker dat er een geldig integer getal in zit. Met mysql_real_escape_string() kan er ook tekst of een andere soort getal in zitten.

Daarnaast is er dan nog steeds SQL-injectie mogelijk bij een query zoals deze:

PHP:
1
$sql = "SELECT * FROM tb_ad WHERE id=".$ad;


Let er op dat voor getallen je geen aanhalingtekens nodig hebt, als de variable $ad dan de waarde "1 OR 1=1" bevat zal mysql_real_escape_string() dat gewoon doorlaten waardoor je query opeens verandert naar dit:

SQL:
1
SELECT * FROM tb_ad WHERE id=1 OR 1=1

Aan de inhoud van de bovenstaande tekst kunnen geen rechten worden ontleend, tenzij dit expliciet in dit bericht is verwoord.


Acties:
  • 0 Henk 'm!

  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
Johnny schreef op vrijdag 29 augustus 2008 @ 01:25:
[...]


Je query wordt als een string naar de database verstuurd, dus alle gegevens die je daar in verwerkt zijn ook een string daar in.

Voor integers kun je echter beter een functie zoals intval() gebruiken, dan weet je zeker dat er een geldig integer getal in zit. Met mysql_real_escape_string() kan er ook tekst of een andere soort getal in zitten.
Ik maak zoals je hier onder ziet een integer van, of is het zo nog niet voldoende?
Want toen ik dit nog niet had, had ik nog last van die 005/0005 etc bug, maar zo te zien nu niet meer. Tenminste ik krijg het niet voor elkaar.

Nu verder over het SQL-injectie gebeuren, want daar wil ik nou vanaf zijn.

Dus stel ik heb nu dit:
PHP:
1
2
3
4
5
6
//Ik maak hier van de ad in de url een integer.
$ads=limpiar($_GET["ad"]);
$ad = (int) $ads; 

$sql = "SELECT * FROM tb_ads WHERE id='$ad'";
etc...


Hoe moet ik dan die $sql statement doen?

Zoals hieronder lijkt mij fout, aangezien ik nu een integer in een string doe.

SQL:
1
2
3
4
5
//Ik maak hier van de ad in de url een integer.
$ads=limpiar($_GET["ad"]);
$ad = (int) $ads; 

$sql = "SELECT * FROM tb_ads WHERE id='" . mysql_real_escape_string($ad) . "'";


Zoals hieronder mag niet want dat liet je net zelf zien.

PHP:
1
2
3
4
5
//Ik maak hier van de ad in de url een integer.
$ads=limpiar($_GET["ad"]);
$ad = (int) $ads; 

$sql = "SELECT * FROM tb_ads WHERE id=" .$ad;


Hieronder probeer ik het met PDO, maar verder dan de eerste regel met prepare kom ik niet. Sorry maar, ik snap er weinig van :(

PHP:
1
2
3
4
5
6
7
8
9
10
11
//Ik maak hier van de id in de url een integer.
$ads=limpiar($_GET["ad"]);
$ad = (int) $ads; 

$stmt = $dbh->prepare("SELECT * FROM tb_ads where id = :ad");

en dan..?
Want bij mij zou er als ik gewoon sql zou doen dit gebeuren:

$result = mysql_query($sql);        
$myrow = mysql_fetch_array($result);


Dus iemand die het a.u.b. een keer voor mij goed kan neerzetten, want jullie wijzen me van hort naar her maar ik snap er weinig meer van :(

Als het gaat om sql statements waar geen nummer in voor komt snap ik het nu wel.
Dan word het zo, of ben ik nou helemaal in de war :?
SQL:
1
$sql = "SELECT * FROM tb_users WHERE username='" . mysql_real_escape_string($user) . "'";

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Ja, bij die laatste query zit je goed.

mysql_real_escape_string(): Deze functie escapet strings voor gebruik binnen een mysql context (en hij werkt nog echt ook :+ ). WTF is er onduidelijk aan die functienaam?
Als je weet dat iets een int of float is, cast je het gewoon naar int resp. float. Als je gewoon direct bij het maken van de query wil zien dat je veilig zit, cast of escape je het gewoon altijd op die plek. Ga je niet druk maken over een cast welke mogelijk 100 regels eerder al gebeurd is, weglaten is een micro-optimalisatie en vraagt tevens om problemen bij wijzigingen van het eerdere stuk code.

Maar en dat is deels een ander onderwerp: Je kan gaan balen van het op deze manier low-level opbouwen van query strings, of je wil op een manier werken zodat je de specifieke dbms weg abstraheert etc etc. en dan wil je dus een db abstractielaag en/of prepared statements etc.

Over zowel (my)sql injection als prepared statements als db abstractie lagen is veel geschreven, dus verdiep je gewoon eens, voordat wij al die tutorials in dit topic moeten copy pasten en dit topic dus het eerst GoT topic met 10 miljoen replies wordt. En ja, er is echt al zoveel over gekletst.

[ Voor 11% gewijzigd door Voutloos op 29-08-2008 08:17 ]

{signature}


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Je kunt ook de ctype functies gebruiken, werkt erg simpel:

PHP:
1
2
3
4
if(TRUE === ctype_digit($_GET['a']))
{
    // je weet nu zeker dat $_GET['a'] een getal is...
}


Het casten naar een integer met (int)$_GET['a'] laat bijv -5, 1e10, 0x1A gewoon door terwijl dat misschien (en zeer waarschijnlijk) niet wenselijk is.

[ Voor 6% gewijzigd door Cartman! op 29-08-2008 11:27 ]


Acties:
  • 0 Henk 'm!

  • remmelt
  • Registratie: Januari 2001
  • Laatst online: 09-04 12:25
Voorbeeld #3 van de gelinkte PDO pagina (beetje aangepast):
PHP:
1
2
3
4
5
6
7
8
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = :name");
$stmt->bindParam(':name', $name);

if ($stmt->execute()) {
  while ($row = $stmt->fetch()) {
    print_r($row);
  }
}


Let op: normaal doe je SELECT * FROM table WHERE name = 'hans';
Je doet dus enkele quotes om de strings heen. Bij ints doe je dat niet:
SELECT * FROM table WHERE id=3;
Daar laat je de quotes natuurlijk weg, omdat het geen string (of datum) is, maar een getal.

Bij PDO is dat onderscheid weggeabstraheerd, je doet gewoon SELECT * FROM table WHERE name = :name;
Zonder de quotes! Die worden door PDO toegevoegd in de uiteindelijke echte query. Je kan ze dus ook niet meer vergeten.

Even een quote van de PHP pagina:
You are strongly recommended to use PDO::prepare() to prepare SQL statements with bound parameters instead of using PDO::quote() to interpolate user input into a SQL statement. Prepared statements with bound parameters are not only more portable, more convenient, immune to SQL injection, but are often much faster to execute than interpolated queries, as both the server and client side can cache a compiled form of the query.
Daar staat: je hoeft je strings ook niet meer te quoten/escapen, dat doet PDO voor je. Input moet natuurlijk gevalideerd worden, maar dat zit in jouw logica, daar kunnen we nu niks over zeggen.

[ Voor 7% gewijzigd door remmelt op 29-08-2008 10:58 ]


Acties:
  • 0 Henk 'm!

  • Patriot
  • Registratie: December 2004
  • Laatst online: 19:24

Patriot

Fulltime #whatpulsert

Johnny schreef op vrijdag 29 augustus 2008 @ 01:25:
Daarnaast is er dan nog steeds SQL-injectie mogelijk bij een query zoals deze:

PHP:
1
$sql = "SELECT * FROM tb_ad WHERE id=".$ad;
Eh, dat is wel waar, maar houdt er ook even rekening mee dat de TS door jou nu denkt dat zijn manier fout is. Een naar int gecaste string hoef je natuurlijk niet te escapen, dat kan niet eens met mysql_escape_string(). In het geval van de TS klopte zijn query dus gewoon.

PDO gebruiken is natuurlijk de beste optie, maar in principe was hij al bij de oplossing en het lijkt er nu op dat hij alleen maar weer verder van zijn pad af is gebracht.

Acties:
  • 0 Henk 'm!

  • FabiandJ
  • Registratie: Oktober 2001
  • Niet online
Cartman! schreef op vrijdag 29 augustus 2008 @ 10:29:
Je kunt ook de ctype functies gebruiken, werkt erg simpel:

PHP:
1
2
3
4
if(TRUE === ctype_digit($_GET['a']))
{
    // je weet nu zeker dat $_GET['a'] een getal is...
}


Het casten naar een integer met (int)$_GET['a'] laat bijv -5, 1e10, 0x1A gewoon door terwijl dat misschien (en zeer waarschijnlijk) niet wenselijk is.
Klopt dat dat niet gewenst is, maar het probleem was vooral dat als mensen er een 0 voor de id zetten dan werd als nog de pagina geopent. Maar pakken ze gewoon een nummer waar niks achter zit, dan zal er ook niks geladen worden, aangezien dat id niet in de database staat. En pakt men heel toevallig een id die wel bestaat zien ze deze ook op de pagina met het overzicht. En is deze nog niet bezocht de afgelopen 24 uur, zal die na de timer gewoon passen. Proberen ze het daarna opnieuw met datzelfde id of een 0 ervoor, dan zal men een error krijgen. En die error kregen ze dus eerst niet als ze een 0 voor de id zette en dat probleem is opgelost.

Alleen na het posten van hier wat code zijn we iets van het onderwerp afgedwaald en kwam SQL-Injectie te voorschijn, en aangezien we dan toch bezig zijn vraag ik dan meteen hoe het is op te lossen omdat ik mij hier nooit in heb verdiept (my bad).
Patriot schreef op vrijdag 29 augustus 2008 @ 13:15:
[...]


Eh, dat is wel waar, maar houdt er ook even rekening mee dat de TS door jou nu denkt dat zijn manier fout is. Een naar int gecaste string hoef je natuurlijk niet te escapen, dat kan niet eens met mysql_escape_string(). In het geval van de TS klopte zijn query dus gewoon.

PDO gebruiken is natuurlijk de beste optie, maar in principe was hij al bij de oplossing en het lijkt er nu op dat hij alleen maar weer verder van zijn pad af is gebracht.
Kijk iemand is wakker ;)

Maar als ik het nu dus goed begrijp.
Zit er in je sql statement een string, dan gebruik je de mysql_real_escape_string() functie, heb je een integer dan verander je niks, aangezien ik nu alle strings die een integer horen te zijn nu omcast, kan ik dat SQL statement hetzelfde laten.

Al is het gebruiken van PDO het beste, maar dit zet ik dan op de todo lijst.
Aangezien voor als ik de verschillen tussen dat wat ik nu gebruik en PDO, PDO de database minder zal belasten aangezien die pas connectie maakt met de database als alles correct is.

Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Het is alleen een extra 'opweghelpertje' omdat veel mensen denken dat casten naar int voldoende is om een getal over te houden maar vergeten wetenschappelijke en hexadecimale notaties. Wil je dat afvangen dan gebruik je ctype_digit. Zonder escapefunctie zou je 0x1A mooi gezeik op kunnen leveren...

en ja, PDO is zeker de way to go. Zit ingebakken in Zend Framework, handig :)

Acties:
  • 0 Henk 'm!

  • remmelt
  • Registratie: Januari 2001
  • Laatst online: 09-04 12:25
Het verschil tussen wat je nu doet en PDO is dat je je geen zorgen meer hoeft te maken over SQL injectie. Ik snap niet dat je dat dan niet direct gebruikt. Ik vertel je: ik heb die mysql_ functies al jaren niet meer direct gebruikt. Waarom zou je?

Je hoeft je dan alleen maar bezig te houden met je applicatiecode, wat je applicatie verwacht, dus een int op de plek van een int, een string op de plek van een string, of wat dan ook. Je bent niet meer bezig met implementatiegezeur, details waar je eigenlijk helemaal geen tijd in zou moeten stoppen. Je doel is een toffe applicatie te bouwen, niet om een db aan de praat te krijgen.

De directe mysql functies zijn eigenlijk alleen goed voor het leren programmeren in PHP. Je ziet wat er gebeurt en het is allemaal lekker direct. Alles in een bestandje, je hele logica en html en de hele meuk in index.php en attack.php en saldo.php etc.
Leerzaam, maar als je echt wilt beginnen is de eerste stap het inbrengen van verschillende lagen in je code. Lees eens over MVC, model/view/controller, Smarty, etc. PDO is de database abstractielaag die nu in PHP zit ingebakken. Waarom gebruik je dat dan niet?

Wat je nu doet is overal mysql_esacpe_string bij tiepen, of juist niet want het is een int, of wacht, die weer wel, en nu verander ik toch maar m'n db of de code en dan moet ik niet vergeten dat ook weer aan te passen, nou ik zet het op m'n todo lijstje, anyway het werkt nu dus het zal wel.
En dan wordt je database leeggegooid door een of ander script kiddie.
En dan lees je deze thread nog eens terug en denk je, "Oh ja, PDO, dat was achteraf wel slim geweest."
Pagina: 1