voorkomen van SQL-injecties in PHP (en andere kwetsbaarheden)
als je al een tijdje bezig bent met webontwikkeling, heb je bijna zeker gehoord van de term “SQL-injectie” en een aantal angstaanjagende verhalen erover.
PHP is, net als vele andere talen, niet immuun voor dit soort bedreigingen, wat zeer gevaarlijk kan zijn. Maar, gelukkig, het beschermen van uw websites van SQL injectie en andere soortgelijke bedreigingen is iets wat je kunt tastbare stappen in de richting van te nemen.
in dit bericht leert u wat SQL-injectie is, wat de gevolgen zijn van een succesvolle aanval, hoe een aanvaller kan profiteren van kwetsbare PHP-code, wat u kunt doen om het te voorkomen, en welke tools u kunt gebruiken om de delen van uw code te detecteren die onderhevig kunnen zijn aan dit soort bedreigingen. Daarnaast leer je over een paar andere veel voorkomende kwetsbaarheden die je moet weten om veiligere applicaties te maken.
Hoe werkt een SQL-injectie?
het eerste wat u moet weten om uw code te beschermen tegen SQL injectie is om te begrijpen hoe het kan worden uitgebuit door een aanvaller.
het idee achter de exploit is vrij eenvoudig: een aanvaller draait kwaadaardige SQL-code op uw database via uw app.
Hoe kan iemand dat bereiken? Door misbruik te maken van de input van uw applicatie.
laten we een eenvoudig voorbeeld bekijken. Stel dat je een toepassing hebt die een lijst met Gebruikersnamen toont, waarbij elke gebruiker een link heeft naar hun details, zoals:
en dan, op het user_details.php
bestand, heb je dit:
<?php $sql = "SELECT * FROM user WHERE id = ".$_GET;
als de gebruiker handelt zoals verwacht en op de naam van een gebruiker klikt, ziet de URL van het verzoek er als volgt uit: http://domain.com/user_details.php?id=8
.
dus, wat is er mis mee?
de waarde van $sql
zal de tekenreeks "SELECT * FROM user WHERE id = 8"
zijn en de query zal prima draaien.
het probleem zit in het cursieve gedeelte van deze zin: als de gebruiker handelt zoals verwacht en op de naam van een gebruiker klikt, zal de URL van het verzoek er zo uitzien:
http://domain.com/user_details.php?id=8
.
wat als de gebruiker niet handelt zoals verwacht?
wat als iemand een URL maakt die iets anders dan een nummer als ID stuurt?
vervaardigde URL ‘ s
als de URL ongeveer http://domain.com/user_details.php?id=Peanuts
was, zou de resulterende SQL-string zijn: "SELECT * FROM user WHERE id = Peanuts"
.
In dit geval is het probleem voor de gebruiker. De query zou gewoon mislukken, en, in een worst-case scenario, de gebruiker zou een soort raar bericht te zien.
maar wat als de URL er meer zo uitzag:
http://domain.com/user_details.php?id=1+OR+1%3B
? (Dit is trouwens het resultaat van urlencode('1 OR 1;')
.)
In dit geval zou de resulterende SQL "SELECT * FROM user WHERE id = 1 OR 1;"
zijn. Dat betekent dat het resultaat van de query elke gebruiker in de database zou zijn in plaats van alleen de gebruiker wiens ID gelijk is aan 1. Au.
maar dat is nog steeds niet zo slecht, toch?
laten we nu een extremer voorbeeld proberen.
stel dat de URL zoiets was
http://domain.com/user_details.php?id=1%27%3B+DROP+TABLE+users%3B--+
, wat zich vertaalt in id=1; DROP TABLE users;--
, waardoor dit SQL-commando effectief wordt geproduceerd:
"SELECT * FROM users WHERE id = 1; DROP TABLE users;-- "
. En als je deze zoekopdracht uitvoert …
indien u niet 100% bekend bent met SQL-syntaxis, zou DROP TABLE
de tabel volledig verwijderen. Het zou zijn alsof het nooit heeft bestaan.
natuurlijk zou een recente back-up de schade helpen verminderen, maar toch. Dit is slecht.
Als u meer wilt weten over dit soort aanvallen, is er een geweldig bericht hier.
maar ik denk dat dat genoeg slecht nieuws is. Laten we verder gaan naar een meer vrolijke plek: hoe je dit soort SQL-injecties kunt voorkomen in je PHP-apps.
hoe SQL-injecties te voorkomen in PHP
zoals u zag, is het probleem wanneer een aanvaller de mogelijkheid heeft om SQL-code uit te voeren zonder dat u zich ervan bewust bent.
deze situatie doet zich voor als gevolg van het hebben van query ‘ s gemaakt op de fly via string concatenation en met inbegrip van gegevens verzameld van externe input (meestal user input, maar ook andere externe bronnen zoals bestanden, reacties op API calls, enzovoort).
dus, om deze kwetsbaarheid in uw code te voorkomen, moet u de bronnen van potentiële problemen oplossen.
Valideer uw invoer
een eenvoudige manier om de kwetsbaarheid in het bovenstaande voorbeeld op te lossen zou zijn om te controleren of de id parameter is wat er werkelijk van wordt verwacht (d.w.z., een positief geheel getal):
een andere manier om dit soort validatie te doen is door gebruik te maken van PHP ‘ s ingebouwde filters:
<?php
$id = filter_input( INPUT_GET, 'id', FILTER_VALIDATE_INT);
zo, door het valideren van uw ingangen, voorkomt u aanvallers van het uitvoeren van kwaadaardige code naast uw eigen.
er is geen gemakkelijke manier om te voorkomen dat ze het proberen, maar zolang hun pogingen niet succesvol zijn, ben je klaar om te gaan.
gebruik ‘prepared statements’
een andere manier waarop u uw code kunt beschermen tegen SQL-injecties is door ‘prepared statements’ te gebruiken. Prepared statements zijn voorgecompileerde SQL commando ‘ s.
ze kunnen worden gebruikt met een specifieke database toegangsbibliotheek (zoals mysqli) of met de meer generieke bibliotheek Bob.
laten we eens kijken naar een voorbeeld met behulp van mysqli:
als u deze code probeert (het vervangen van de database referenties, natuurlijk), zult u zien dat, indien benaderd via een juridische URL zoals http://domain.com/user_details.php?id=1
, u hetzelfde resultaat krijgt als een van de kwaadaardige URL ‘ s hierboven (dat is de informatie over de gebruiker geassocieerd met ID 1 en niets anders).
als u liever Bob gebruikt, ziet de code er meer als volgt uit:
niet echt veel verschil, toch?
samengevat bieden voorbereide verklaringen een geweldige manier om SQL-injecties te voorkomen. Ook, ze meestal beter presteren dan on-The-fly SQL.
Nu u het gereedschap kent, hoeft u het alleen maar te gebruiken.
hoe PHP-code te detecteren die kwetsbaar is voor SQL-injecties
zodra de kwetsbaarheid is gevonden, is de vaststelling ervan niet echt ingewikkeld. Maar hoe vind je dit soort kwetsbaarheden in je code in de eerste plaats?
als je geluk hebt en je codebase klein genoeg is, is een eenvoudige herziening van de code voldoende.
maar als uw toepassing middelgroot tot groot is, hebt u extra hulp nodig.
een zeer populaire (en open-source) tool die u kunt gebruiken voor dit doel is sqlmap, een eenvoudig Python script dat zal proberen om elke URL die u feed om het aan te vallen en verslag uit te brengen over de bevindingen.
hier is een voorbeeld van een run tegen een PHP-gebaseerde website van mij:
een andere open-source tool die u kunt gebruiken is Arachni, een meer geavanceerde tool die een web GUI bevat en is geschreven in Ruby.
hier is een voorbeeld van het uitvoeren van het door de CLI:
naast het beoordelen en testen van code, moet u overwegen om een RASP-oplossing, zoals Sqreen, te gebruiken om uw productie-omgevingen te controleren om de uitvoering te stoppen van exploits die het door de beoordeling en testen fasen halen.
welke andere kwetsbaarheden moet u weten?
Code-injecties
SQL-injectie is slechts één lid van een grotere groep kwetsbaarheden: code-injectie.
het idee achter verschillende codeinjectietechnieken is altijd hetzelfde. Het draait allemaal om het misleiden van een onschuldige toepassing in het uitvoeren van kwaadaardige code.
dit kan op verschillende manieren.
in PHP zijn er functies ontworpen om commando ‘ s direct in het besturingssysteem uit te geven, zoals de exec
functie.
hier is een eenvoudig voorbeeld van hoe dit zou kunnen worden benut:
<?php
exec( 'cp uploads/'.$_GET.' /secure/');
als iemand http://domain.com/exec.php?file=a.txt%3B+rm+-Rf+%2A+%23
zou vragen, zou het resultaat de uitvoering van dit commando zijn.:
cp uploads/a.txt; rm -Rf * # /secure/
en dit kan de hele schijf op de server wegvagen-niet-gevalideerde invoer slaat weer toe!
cross-site scripting
een andere veel voorkomende kwetsbaarheid is cross-site scripting (XSS). In dit geval, het slachtoffer is de gebruiker een bezoek aan uw site.
XSS is wanneer een aanvaller kwaadaardige JavaScript-code injecteert in een gewone HTML-vorm, die later zal worden weergegeven door de browser van een andere gebruiker.
Kijk naar Dit PHP script:
<?php
echo "<html><p>Hello {$_GET}!</p></html>";
het is duidelijk dat de bedoeling hier is om een eenvoudige pagina te maken die de gebruiker begroet.
maar wanneer slechteriken het krijgen, wat weerhoudt hen om te vragen
http://domain.com/greet.php?name=Mauro%3Cscript+language%3D%22javascript%22%3Ealert%28%22You+are+hacked%21%22%29%3B%3C%2Fscript%3E
? Dit verzoek zal de volgende HTML als uitvoer produceren:
<html><p>Hello Mauro<script language="javascript">alert("You are hacked!");</script></p></html>
Dit is duidelijk een zeer naïeve exploit-immers, wat is het kwaad in het tonen van iemand een eenvoudige ” je bent gehackt!”boodschap? Maar dingen kunnen behoorlijk serieus worden met een beetje fantasie. Houd er rekening mee dat elk verzoek aan een server bevat de sessie cookie, zodat deze kwetsbaarheid kan de boosdoener achter sessies van uw gebruikers krijgen gekaapt.
hoewel de problemen er lelijk uitzien, zijn de oplossingen heel eenvoudig: het draait allemaal om validatie en ontsmetting.
in het geval van XSS is een eenvoudige aanroep naar htmlentities
voor het produceren van de werkelijke output voldoende.
oplossen Versus detecteren van beveiligingsproblemen
zoals u in dit bericht zag, is het oplossen van beveiligingsproblemen—zowel SQL—injecties als andere typen-niet de belangrijkste uitdaging. Realiseren dat uw code is kwetsbaar, en waar het kan worden benut, is. Je hebt een paar opties hier:
- heb een zeer sterke coderingsdiscipline
- Test uw applicaties grondig op beveiligingsproblemen
- gebruik monitoring-en beschermingstools om exploits te voorkomen en tijdig waarschuwingen te ontvangen
welke u kiest is aan u. Het belangrijkste is om aandacht te besteden aan deze problemen en handelen op die kennis. Blijf veilig.