SQL Injection — Impossible
Op het Impossible niveau gaan we kijken hoe de kwetsbaarheid daadwerkelijk professioneel wordt opgelost.
1. Predict (Voorspel)
De code is volledig herschreven en ziet er nu ongeveer zo uit (met behulp van PDO: PHP Data Objects):
$stmt = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$stmt->bindParam( ':id', $id, PDO::PARAM_INT );
$stmt->execute();
Vraag: Waarom is het invoeren van 1' OR '1'='1 hier volstrekt nutteloos?
Antwoord
De code gebruikt Prepared Statements. Dit is de gouden standaard tegen SQL Injection.
Hierbij wordt de structuur van het SQL commando alvast naar de database gestuurd, vóórdat de variabelen worden toegevoegd.
De database wéét hierdoor precies wat commando's zijn en wat data is. Als je nu 1' OR '1'='1 invult, denkt de database: "Ah, deze persoon is op zoek naar een gebruiker wiens naam/id letterlijk de tekst '1' OR '1'='1' is." Hij voert het dus niet meer uit als code!
Bovendien dwingt PDO::PARAM_INT af dat de invoer een wiskundig getal (integer) móét zijn.
2. Run & Investigate
Start het lab en probeer je beste SQL injection hacks.
Je zult zien dat het onmogelijk is. De applicatie gedraagt zich alsof je een rare zoekopdracht hebt ingetikt en geeft simpelweg nul resultaten terug.
3. ✓ Wat moest je zien?
- Welk payload je ook typt (
1' OR '1'='1,1 UNION SELECT…,1; DROP TABLE…): altijd nul resultaten of de melding "Gebruiker niet gevonden". - Géén SQL-foutmelding, géén stack trace, géén verraderlijke informatie over de database.
- Vergelijk de broncode met die van Low/Medium/High — zoek naar
prepare(,bindParam, enPDO::PARAM_INT. Dat is wat je in productie wilt zien.
Zie je tóch resultaten of fouten? Dan ben je per ongeluk teruggesprongen naar een lager niveau — controleer het level-bordje rechtsboven in het lab.
Wat heb je geleerd?
- String Concatination is levensgevaarlijk: Het plakken van gebruikersinvoer in SQL queries via
$query = "SELECT * FROM users WHERE id = " . $id;leidt gegarandeerd tot SQL injection. - Escape functies zijn onbetrouwbaar: Functies zoals
mysqli_real_escape_stringkunnen onder bepaalde omstandigheden omzeild worden (bijv. als aanhalingstekens in de query ontbreken). - Prepared Statements: Dit is de énige 100% waterdichte verdediging tegen SQL Injection. Gebruik altijd PDO of vergelijkbare libraries in andere programmeertalen.