SQL-injecties vormen een aanzienlijke bedreiging voor relationele databasemodellen en de gevoelige informatie die ze bevatten. Daarom is uitgebreide bescherming tegen deze ongeoorloofde externe toegangs pogingen – mogelijk gemaakt door beveiligingslekken – absoluut essentieel.

Wat is een SQL-injectie?

Een SQL-injectie is een type aanval dat misbruik maakt van een beveiligingslek in relationele databasesystemen die de SQL -querytaal gebruiken om gebruikersinvoer te verwerken. De aanvaller maakt misbruik van gebruikersinvoer die niet goed is geëscape en speciale tekens bevat, zoals dubbele koppeltekens, aanhalingstekens of puntkomma’s. Deze tekens hebben speciale functies voor de SQL-interpreter en maken het mogelijk om de uitgevoerde commando’s extern te manipuleren. SQL-injecties worden vaak geassocieerd met PHP- en ASP-toepassingen die gebruikmaken van verouderde interfaces. In veel van deze gevallen wordt de invoer niet voldoende gezuiverd, waardoor deze een belangrijk doelwit voor aanvallen vormt.

Door strategisch functiekarakters in te voegen, kan een onbevoegde gebruiker extra SQL-opdrachten invoegen en database-items manipuleren om gegevens te lezen, te wijzigen of te verwijderen. In ernstige gevallen kunnen aanvallers zelfs toegang krijgen tot de opdrachtregel van het systeem, waardoor ze volledige controle over de databaseserver kunnen krijgen.

Voorbeeld van SQL-injectie dat laat zien hoe een database-aanval werkt

Omdat kwetsbare databaseservers snel kunnen worden geïdentificeerd en SQL-injectieaanvallen relatief eenvoudig uit te voeren zijn, blijft deze methode een van de meest gebruikte technieken onder cybercriminelen wereldwijd. Aanvallers gebruiken verschillende strategieën en maken daarbij misbruik van zowel nieuw ontdekte als al lang bestaande beveiligingsfouten in de applicaties die betrokken zijn bij het gegevensbeheerproces. Om beter te begrijpen hoe SQL-injectie in de praktijk werkt, bekijken we twee veelvoorkomende aanvalsmethoden als voorbeeld.

Voorbeeld 1: Toegang via slecht geëscapeerde gebruikersinvoer

Om toegang te krijgen tot een database moeten gebruikers zich meestal eerst authenticeren. Hiervoor worden vaak scripts gebruikt om een inlogformulier weer te geven met velden voor een gebruikersnaam en wachtwoord. Gebruikers vullen het formulier in en het script controleert vervolgens of er overeenkomende gegevens in de database staan. Standaard bevat de database mogelijk een tabel met de naam users en de kolommen username en password. In een typische webapplicatie kunnen de relevante scriptregels voor databasetoegang (met behulp van Python-achtige pseudocode) er als volgt uitzien:

uname = request.POST['username']
passwd = request.POST['password']
sql = "SELECT id FROM users WHERE username='" + uname + "' AND password='" + passwd + "'"
database.execute(sql)
python

Een aanvaller kan nu het wachtwoordveld manipuleren met behulp van een SQL-injectie, bijvoorbeeld door password' OR 1='1 in te voeren, wat resulteert in de volgende SQL-query:

sql = "SELECT id FROM users WHERE username='' AND password='password' OR 1='1'"
python

Hierdoor krijgt de aanvaller volledige toegang tot de volledige gebruikerstabel in de database, aangezien de wachtwoordvoorwaarde altijd als waar wordt beoordeeld (1='1'). Als de aanvaller zich aanmeldt als beheerder, kan hij alle database-items vrijelijk wijzigen. Als alternatief kan het veld voor de gebruikersnaam op dezelfde manier worden gemanipuleerd.

Voorbeeld 2: Gegevensverzameling via ID-manipulatie

Het opvragen van informatie uit een database op basis van een ID is een praktische en veelgebruikte methode, maar opent ook een mogelijke deur voor SQL-injectie. Een webserver weet bijvoorbeeld via een verzonden ID-detail in een URL welke informatie hij uit de database moet ophalen. Het bijbehorende PHP-script ziet er als volgt uit:

<?php
    $mysqli = new mysqli("localhost", "username", "password", "database");
    $id = intval($_GET['id']);
    $result = $mysqli->query("SELECT * FROM table WHERE id=$id");
    while ($row = $result->fetch_assoc()) {
        echo print_r($row, true);
    }
?>
php

De verwachte URL volgt het patroon .../script.php?id=22. In dit geval zou de tabelvermelding met ID ‘22’ worden opgehaald. Als een onbevoegde persoon de mogelijkheid heeft om deze URL te manipuleren en in plaats daarvan een verzoek zoals .../script.php?id=22+OR+1=1 verstuurt, zal de resulterende query ervoor zorgen dat alle rijen in de tabel worden opgehaald:

SELECT * FROM table WHERE id=22 OR 1=1;
sql

Hoe vinden criminelen kwetsbare databasesystemen?

In principe kan elke website of webapplicatie die gebruikmaakt van SQL-databases zonder voorbereide query’s (prepared statements) of andere beschermende maatregelen kwetsbaar zijn voor SQL-injecties. Ontdekte kwetsbaarheden blijven niet lang verborgen op het wereldwijde web. Er zijn zelfs websites die actuele lijsten met bekende beveiligingsfouten publiceren en zelfs uitleggen hoe aanvallers Google-zoekopdrachten kunnen gebruiken om overeenkomende webprojecten te vinden. Als een website gedetailleerde SQL-foutmeldingen retourneert, kunnen cybercriminelen die meldingen gebruiken om potentiële kwetsbaarheden te identificeren. Het toevoegen van een apostrof aan het einde van een URL met een ID-parameter kan bijvoorbeeld al een zwakke plek blootleggen, zoals te zien is in het volgende voorbeeld:

[DomainName].com/news.php?id=5’

Een kwetsbare website stuurt een foutmelding terug in de volgende vorm:

Query failed: You have an error in your SQL syntax…

Soortgelijke methoden kunnen ook worden gebruikt om het aantal kolommen, tabel- en kolomnamen, de SQL-versie of zelfs gebruikersnamen en wachtwoorden te achterhalen. Daarnaast bestaan er verschillende tools die zowel het detectieproces als de uitvoering van SQL-injectieaanvallen kunnen automatiseren.

Hoe u uw database kunt beschermen tegen SQL-injectie

Er zijn verschillende methoden die u kunt gebruiken om SQL-injectieaanvallen op uw databasesysteem te voorkomen. U moet alle betrokken componenten aanpakken: de server, de afzonderlijke applicaties en het databasebeheersysteem.

Stap 1: Controleer geautomatiseerde invoer vanuit applicaties

Bij het verwerken van invoer van externe of ingebouwde applicaties is het essentieel om de ingediende waarden te valideren en te filteren om SQL-injecties te voorkomen.

1. Gegevenssoorten valideren

Elke invoer moet overeenkomen met het verwachte gegevenstype. Als er bijvoorbeeld een numerieke invoer vereist is, zou een eenvoudige validatie in PHP er als volgt kunnen uitzien:

if (filter_var($input, FILTER_VALIDATE_INT) === false) {
    throw new InvalidArgumentException("Invalid input");
}
php

Soortgelijke controles moeten worden uitgevoerd voor strings, datums of andere specifieke formaten.

2. Speciale tekens filteren

Speciale tekens kunnen beveiligingsrisico’s opleveren, vooral in SQL- of HTML-contexten. Een veilige aanpak is om htmlspecialchars() te gebruiken voor HTML-invoer en PDO::quote() voor SQL-query’s.

3. Vermijd het weergeven van foutmeldingen

Directe foutmeldingen die technische details over de database of het systeem onthullen, moeten worden vermeden. Geef in plaats daarvan een algemene melding weer, zoals:

echo "An error occurred. Please try again later.";
error_log("Unexpected error encountered. See system log for details.");
php

4. Gebruik voorbereide verklaringen

Een van de meest effectieve manieren om SQL-injecties te voorkomen, is door gebruik te maken van voorbereide statements. Bij deze aanpak worden SQL-commando’s en parameters afzonderlijk verzonden, zodat kwaadaardige code niet kan worden uitgevoerd. Hier volgt een voorbeeld van een implementatie in PHP met behulp van PDO (PHP Data Objects):

$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->bindParam(':id', $user_id, PDO::PARAM_INT);
$stmt->execute();
php

Het databasebeheersysteem zorgt er automatisch voor dat de invoer veilig wordt verwerkt.

Stap 2: Zorg voor uitgebreide serverbeveiliging

De beveiliging van de server waarop uw databasebeheersysteem draait, speelt ook een cruciale rol bij het voorkomen van SQL-injectie. Een belangrijke maatregel is het versterken van het besturingssysteem door deze best practices te volgen:

  • Installeer of schakel alleen de applicaties en services in die essentieel zijn voor het uitvoeren van de database.
  • Verwijder alle ongebruikte of onnodige gebruikersaccounts.
  • Zorg ervoor dat alle relevante systeem- en software-updates onmiddellijk worden geïnstalleerd.
  • Pas het principe van minimale rechten toe om ervoor te zorgen dat gebruikers en services alleen de minimaal noodzakelijke rechten krijgen.

Afhankelijk van de beveiligingsvereisten van uw webproject, moet u aanvullende beschermende maatregelen overwegen:

  • Intrusion Detection Systems (IDS) en Intrusion Prevention Systems (IPS): Deze systemen gebruiken verschillende detectiemethoden om aanvallen vroegtijdig te identificeren, waarschuwingen te geven en – bij gebruik van IPS – automatisch tegenmaatregelen te nemen.
  • Application Layer Gateway (ALG): Een ALG controleert en filtert het verkeer tussen applicaties en webbrowsers rechtstreeks op applicatieniveau.
  • Web Application Firewall (WAF): Een WAF beschermt webapplicaties specifiek tegen SQL-injectie en Cross-Site Scripting (XSS) door verdachte verzoeken te blokkeren of te zuiveren.
  • Zero Trust-benadering: Dit moderne beveiligingsmodel zorgt ervoor dat elke toegangs poging – ongeacht de herkomst ervan – wordt geverifieerd en geauthenticeerd voordat toegang wordt verleend.
  • Firewallregels en netwerksegmentatie: deze zijn essentieel om het aanvalsoppervlak op lange termijn te minimaliseren.
  • Regelmatige IT-beveiligingsaudits en penetratietests: deze helpen kwetsbaarheden in een vroeg stadium op te sporen en te verhelpen.

Stap 3: Versterk de database en gebruik veilige code

Net als uw besturingssysteem moet uw database worden ontdaan van alle overbodige componenten en up-to-date worden gehouden. Verwijder alle opgeslagen procedures die u niet nodig hebt en schakel alle ongebruikte services en gebruikersaccounts uit. Maak een speciaal databaseaccount aan dat uitsluitend bedoeld is voor webtoegang en wijs hieraan alleen de minimaal vereiste machtigingen toe.

In overeenstemming met het gebruik van voorbereide statements wordt sterk aanbevolen om de mysql PHP-module (die in PHP 7 is verwijderd) niet te gebruiken. Kies in plaats daarvan voor mysqli of PDO om een betere beveiliging en compatibiliteit te garanderen. Een veilige mysqli query zou er als volgt uit kunnen zien:

$mysqli = new mysqli("localhost", "username", "password", "database");
if ($mysqli->connect_error) die("Connection failed");
$stmt = $mysqli->prepare("SELECT password FROM users WHERE username = ?");
$stmt->bind_param("s", $_POST['username']);
$stmt->execute();
$stmt->bind_result($hashedPassword);
if ($stmt->fetch() && password_verify($_POST['password'], $hashedPassword)) {
    echo "Login successful";
} else {
    echo "Invalid login credentials";
}
$stmt->close();
$mysqli->close();
php

Wachtwoorden mogen nooit rechtstreeks in een database worden opgeslagen of in platte tekst worden opgehaald. Gebruik in plaats daarvan een hashmethode zoals password_hash() in combinatie met password_verify() om inloggegevens veilig te beschermen. Een veilige implementatie zou er als volgt uit kunnen zien:

$mysqli = new mysqli("localhost", "username", "password", "database");
$stmt = $mysqli->prepare("SELECT password FROM users WHERE username = ?");
$stmt->bind_param("s", $_POST['username']);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
if ($row && password_verify($_POST['password'], $row['password'])) {
    echo "Login successful!";
} else {
    echo "Incorrect username or password.";
}
php

Wat hebben bobby tables te maken met SQL-injectie?

De website bobby-tables.com gebruikt een xkcd-webcomic om op humoristische wijze de gevaren van onveilige gebruikersinvoer in databases te illustreren. In de strip krijgt een moeder een telefoontje van de school van haar zoon (liefkozend Little Bobby Tables genoemd). De beller vraagt of haar zoon echt Robert'); DROP TABLE Students;-- heet, waarop zij bevestigend antwoordt. De reden voor het telefoontje wordt al snel duidelijk: door Robert in de studentendatabase in te voeren, werd de hele studententabel gewist. De moeder is niet erg begripvol – ze hoopt alleen dat de school zijn lesje heeft geleerd en voortaan de database-invoer zal opschonen.

De strip laat duidelijk zien welke rampzalige gevolgen het kan hebben als je de invoer van gebruikers in databasetoepassingen niet goed valideert en opschoont.

Ga naar hoofdmenu