SQL injections
02-10-2009 10:15
Offline Stuur privëbericht
SQL injection


Voorbeeld #1
De cracker kan SQL uitvoeren in je script. Laten we maar meteen beginnen met een voorbeeld. In dit voorbeeld wordt een script uitgevoerd die alle gebruikers van een webpagina laat zien. De bezoeker kan die lijst sorteren zodat alle gebruikers namen met een A vooraan en met een Z achteraan komen te staan in die lijst en omgekeerd. Deze opzet komt veel voor op het internet.

Code | Selecteer Alles
minimaliseren
1
2
3
4
5
<?php 
// script.php?order=desc 
$query mysql_query('SELECT username FROM users ORDER BY username '.$_GET['ORDER']); 
// show it 
?>


Je kan in SQL meerdere queries uitvoeren, door iedere query met een ';' af te sluiten. Raad maar eens wat er gebeurt als ik het script als volgt aanroep:

Code | Selecteer Alles
minimaliseren
1
script.php?order=descDROP TABLE users


Inderdaad, de tabel 'users' zal verwijderd worden.

Voorbeeld #2
Nog een voorbeeld, je hebt een database opgezet waarin de gebruikers van jouw site hun persoonlijke bestanden in kunnen zetten. Je slaat de bestanden op in een directory en de bestandsnaam geef je een random naam. In de database heb je de echte naam van het bestand opgeslagen en een verwijzing naar de random naam:

Code | Selecteer Alles
minimaliseren
1
2
3
4
5
6
7
Content map files 
kdjeijfjiejfjijeifjef
.doc 33 kb 
werklnmwekorje
.txt 3 kb 
Content db tabel files 
id user_id filename random_name 
1 1 cv
.doc kdjeijfjiejfjijeifjef.doc 
2 2 passwords
.doc werklnmwekorje.txt


en het volgende script heb je draaien:

Code | Selecteer Alles
minimaliseren
1
2
3
4
5
6
7
8
9
10
<?php 
# files.php 
if (!isset($_GET['login_id'])) 
exit(
'please log in!'); 
$id $_GET['id']; # $_GET['id'] is (let's say) an unique ID from 10 chars; not guessable 
$query mysql_query('SELECT * FROM files WHERE id = '.$_GET['login_id']); 
print 
'Your documents: '
while (
$row mysql_fetch_assoc($query)) 
print 
'<a href="/files/'.$row['random_name'].'">'.$row['filename'].'</a>'
?>


Wat zou er gebeuren als je het document als volgt aanroept?

files.php?login_id=1234567890 OR 1=1

De volgende SQL query wordt uitgevoerd:

Code | Selecteer Alles
minimaliseren
1
SELECT FROM files WHERE id 1234567890 OR 1=1


En ja hoor, alle persoonlijke bestanden die in de database zitten worden weergegeven! Niet de bedoeling dus! SQL injection is een serieus probleem, onderschat het niet.

Oplossing

Vertrouw nooit de user input die gebruikt wordt in een query. Als je de PHP optie magic_quotes_gpc op 'false' hebt staan, gebruik dan altijd addslashes() bij variabelen die je in een query gebruikt en gebruik altijd quotes bij statements in het WHERE gedeelte van een query. Dus dit is veilig:

Code | Selecteer Alles
minimaliseren
1
2
3
4
5
6
<? 
$artikel 
$_GET['artikel']; 
if (!
ini_get('magic_quotes_gpc')) // check if the option is enabled 
$artikel addslashes($artikel); 
$query mysql_query("SELECT iets FROM table WHERE artikel = '$artikel' ");
?>


Gebruikt slashes in het WHERE gedeelte: WHERE artikel = 'content tussen quotes'
1. Zorg er dus altijd voor dat (in dit geval) $artikel door addslashes() wordt gehaald.
2. Zorg er altijd voor dat waar die van een user komt altijd tussen quotes staat in een query.

Valid SQL houdt ondermeer in dat je bij een numeriek SQL veld geen slashes moet gebruiken in de WHERE statement. Controleer dan ook altijd of de waarde van die numerieke veld ook numeriek is! Anders stel je je site open voor SQL injection. Dus hoe het wel moet bij numerieke velden:

Code | Selecteer Alles
minimaliseren
1
2
3
4
5
6
<?php 
$id 
1// (default) 
if (is_numeric($_GET['id'])) 
$id $_GET['id']; 
mysql_query ("SELECT * FROM table WHERE id=$id"); 
?>


Verder wil ik jullie er nog op wijzen dat ge-encrypte data uit een cookie of uit een URL variabele altijd nog geaddslashed() moeten worden. Voorbeeld van een script die vatbaar is voor SQL injection:

Code | Selecteer Alles
minimaliseren
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php 
// script.php 
// if the cookie with the user info is set, read it and get the e-mail address of the user from the 
SQL database 
if (isset($_COOKIE['user_info'])) { 
$data base64_decode($_COOKIE['user_info']); 
list (
$id$username$password) = explode(':'$data); 
$query mysql_query("SELECT email FROM members WHERE id = '$id' AND password = '$password'"); 
print 
mysql_result($query0'email'); 

// save our user info 
else { 
$id 1
$user 'trouby'
$pass md5('secretpasswd'); 
$content base64_encode("$id:$user:$pass"); 
// $content will now be 'MTp0cm91Ynk6M2U5YzliNzcxZGZkY2QyMjlhMTk0MDE1ZmViYTQ1MWM=' 
setcookie('user_info'$content); 
header('Location: script.php'); 

?>


Je eerst indruk zal zijn dat er niks mis is met dit script, maar schijn bedriegt. De cookie wordt automatisch door addslashes() gehaald, dus daar ligt het niet aan, maar we vergeten 1 ding, de cookie is ge-base64 encoded. Dus de string 'Mtp0cm91Ynk6M2U5YzliNzcxZGZkY2QyMjlhMTk0MDE1ZmViYTQ1MWM=' wordt door addslashes() gehaald. De decoded string is niet door addslashes() gehaald en die wordt in dit script ook niet door addslashes() gehaald, foute boel dus. Hoe buit je dit lek uit? Draai dit PHP script:

Code | Selecteer Alles
minimaliseren
1
2
3
<?php 
print base64_encode("1:blabla:blabla'; SOME SQL; SELECT * FROM members WHERE id = '1"); 
?>


Ze de uitkomst daarvan als cookie. Het script zal nu het volgende uitvoeren in haar query:

SELECT email FROM members WHERE id = '1' AND password = 'blabla'; SOME SQL; SELECT * FROM members WHERE id = '1'

Wanneer je dus encoding of encrypty gebruikt in een cookie, post of get variabele, gebruikt dan addslashes() over de decoded of decrypted waarde!

Als je de SQL injection hacks nog steeds niet erg goed snapt, dan doe je er goed aan om eens naar wat meer voorbeelden te kijken:

PHP manual SQL injection http://www.php.net/manual/en/security.database.php
PHP-Nuke hack http://www.wiretrip.net/rfp/txt/rfp2101.txt
PacketStorm hack http://www.wiretrip.net/rfp/txt/rfp2k01.txt

Noot
De functie mysql_query() staat niet toe om meerdere queries uit te voeren, hoewel SQL dat wel toestaat. De
bovenstaande voorbeelden waarbij meerdere queries worden uitgevoerd, gescheiden door een ';' zullen
daarom niet werken via de PHP functie mysql_query(). SQL ondersteunt wel meerdere queries dus daarom
heb ik ook meerdere querie hacks opgenomen in mijn voorbeelden.
Er werd nog geen reactie geplaatst.