Veiligheid, hoe zorg ik dat mijn site niet gehacked kan worden?

Info 
Door: kokx Moeilijkheidsgraad: 2/3
Views:11.738Reacties: 4(Bekijken)
  Log in om zelf te reageren
 Waardering:10/10 (3 stemmen)



Veiligheid van je site


Aangezien ik de laatste tijd hier op WSM merk dat er steeds minder beveiligde sites zijn, dacht ik dat het tijd was voor een beveiligings tutorial. Het grote voorbeeld hiervan was dit topic: http://www.websitemaken.be/forum/viewtopic.php?p=105957#105957. Hierbij had ik een php file weten te uploaden d.m.v. een verkeerd geschreven upload formulier. Ik leer jullie hier niet hoe je moet hacken, maar hoe je dat moet voorkomen.

Header injection


Ja, meteen ga ik al met zo'n moeilijke term smijten. Header injection is het manipuleren van de request headers zodat je daar heel leuke dingen mee kan doen. Dit heb ik ook gedaan met dat upload formulier. Dit is de meest voorkomende manier van het hacken van sites, gezien je hier vaak PHP bestanden mee kan uploaden, waardoor je eigenlijk alles kan doen wat je wilt.

Hoe voorkom je Header injection?


Controleer ALLE user-input. Dus niet alleen de $_FILES, $_POST en $_GET variabelen, al zijn dit wel de meest bekende. Maar ook de $_COOKIE var is user-input, en een groot gedeelte van de $_SERVER var ook. Vertrouw hier dus niet op!

Maar nu even het echte gevaar, de $_FILES variabele.

De grote fout is dat mensen denken dat als je de $_FILES['namefromform']['type'] variabele te veel vertrouwen, dat was het exacte probleem bij dit topic. Met header injection verander je de request headers, en het type van geuploade files staat in de request header. Beter gezegd, dat is ook user-input (want de request headers kunnen veranderd worden door een hacker).

Maar hoe ik dat dan anders?
Heel simpel, kijk of de inhoud ook echt een image is (bij het uploaden van images). Ik doe dit met de gd library. Ik gebruik hiervoor deze code:
#Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
switch ($_FILES['namefromform']['type']) {
    
case 'image/png':
    
case 'image/x-png':
        
$img = @imagecreatefrompng($_FILES['namefromform']['tmp_name']);
        
break;
    
case 'image/jpeg':
    
case 'image/pjpeg':
    
case 'image/jpg':
        
$img = @imagecreatefromjpeg($_FILES['namefromform']['tmp_name']);
        
break;
    
case 'image/gif':
        
$img = @imagecreatefromgif($_FILES['namefromform']['tmp_name']);
        
break;
    
default:
        
$img = false;
}

if (!$img) {
    
// de image is ongeldig, geef een error
} else {
    
imagedestroy($img);
}
?>


SQL injection


Dit is ook een heel groot gevaar wat veel mensen over het hoofd zien. Eigenlijk geld hier ook het principe van header injection, controleer alle user-input.

Nu ga ik even een onveilig voorbeeldje schrijven:
#Code
1
2
3
4
5
6
7
8
<?php
$sql    = "SELECT * FROM tabel_met_gevoelige_data WHERE user=" . $_GET['id'];
$result = mysql_query($sql);

while ($array = mysql_fetch_assoc($result)) {
    
echo $array['data'] . '<br /><br />';
}
?>


Dit is ZEER gevaarlijke code. Hiermee zou je alle eventuele gevoelige data uit de tabel ophalen. Door de volgende url in te vullen:
http://www.example.com/onveilig.php?id=1%20OR%201=1

Dan wordt dit de query:
#Code
1
SELECT * FROM tabel_met_gevoelige_data WHERE user=1 OR 1=1

Oftewel, alle rijen worden uit de database opgehaald.

Hoe moet het dan?


Controleer de user input ;). Beter gezegd, controleer of de input van het juiste type is. Id's controleer je bijvoorbeeld met is_numeric(php.net). Zet ook altijd quotes om bepaalde waarden heen bij SQL (let op: PDO gebruikers die prepared statements gebruiken, mogen dit niet doen, dit wordt automatisch gedaan). Gebruik ook altijd een functie als addslashes(php.net) om eventuele quotes (' en ") te blokkeren. Zodat een gebruiker de quotes niet plotseling sluit, waardoor hij alsnog SQL kan gebruiken.

Nu even een voorbeeldje hoe het wel moet:
#Code
1
2
3
4
5
6
7
8
9
<?php
$id = is_numeric($_GET['id']) ? (int) $_GET['id'] : 1;
$sql    = "SELECT * FROM tabel_met_gevoelige_data WHERE user='" . $id . "'";
$result = mysql_query($sql);

while ($array = mysql_fetch_assoc($result)) {
    
echo $array['data'] . '<br /><br />';
}
?>


Als iemand nog vragen heeft over beveiliging, stel je vraag gerust op het forum.

4 reacties
kokx Geplaatst op 20-06-2007 om 20:02
 

Nieuwsposter
Ik gebruik altijd addslashes, aangezien dat gewoon fatsoenlijk ongedaan kan worden met stripslashes.

Over de volledigheid, dat is eigenlijk gewoon onmogelijk ^^. Maar ik denk er over om nog wat er bij te schrijven, over XSS via HTML, en over bruteforcing. Maar ik weet niet of ik daar nog tijd voor kan vinden.

Edit:
@Peck: Je hebt voor een aantal RDBMS'en zulke functies. Voor PDO heb je zelfs de functie PDO::quote(). Welke ook dergelijke dingen doet.
Peck Geplaatst op 20-06-2007 om 15:10
 

Moderator
Goed geschreven, inderdaad, maar het is eigenlijk maar een fractie van de totale webhackerij.
I.p.v. "is_numeric" kan je overigens ook evengoed "intval" gebruiken, ik vind het alleszins makkelijker werken. Als "addslashes" heeft PHP voor MySQL ook een ander alternatief, nl "mysql_real_escape_string". Misschien interessant om erbij te vermelden, dan hebben lezers van deze tut er een optie bij. :)
Maar het is een nette tut :)
Grubolsch Geplaatst op 20-06-2007 om 13:31
 

Moderator
Niets nieuws onder de zon, maar desondanks goed geschreven en interessant. :)
_ms_ Geplaatst op 20-06-2007 om 10:26
 

Moderator
Nette tut!

Pagina 1 

Om te reageren moet je ingelogd zijn.
Nog niet geregistreerd? Doe dat dan nu!


Terug naar gewone pagina

Websitemaken wordt gehost door Nucleus.be, uw Hosting Solution Builder