logo

SQL-injectie

SQL-injectie is een beveiligingsfout in webapplicaties waarbij aanvallers schadelijke SQL-code invoegen via gebruikersinvoer. Hierdoor kunnen ze toegang krijgen tot de inhoud van de database voor gevoelige gegevens, of zelfs de controle over het systeem overnemen. Het is belangrijk om te weten over SQL Injection om webapplicaties veilig te houden.

SQL Injection (SQLi) is een beveiligingsprobleem dat optreedt wanneer een aanvaller de databasequery's van een webapplicatie kan manipuleren door kwaadaardige SQL-code in invoervelden van gebruikers in te voegen. Deze geïnjecteerde query's kunnen de onderliggende database manipuleren om gevoelige gegevens op te halen, te wijzigen of te verwijderen. In sommige gevallen kunnen aanvallers zelfs bevoegdheden escaleren, waardoor ze volledige controle over de database of server krijgen.



sql-injectie' title=

Voorbeeld uit de echte wereld:

In 2019 vond de Capital One Data Breach plaats vanwege een verkeerd geconfigureerde webapplicatie waarmee een aanvaller misbruik kon maken van een SQL-injectiekwetsbaarheid. Dit resulteerde in het lekken van persoonlijke gegevens van meer dan 100 miljoen klanten, waaronder namen, adressen en kredietscores.

Beveiligingsniveau voor SQL-injectie

DVWA biedt vier beveiligingsniveaus voor SQL-injectie, zodat leerlingen kunnen zien hoe verschillende beveiligingen aanvallen beïnvloeden:



1. Lage beveiliging

De app neemt uw invoer en plaatst deze rechtstreeks in de SQL-query, zonder filtering.

$id = $_GET['id'];$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';
  • Binnenkomen ': Breekt de query af en zorgt ervoor dat de database een fout genereert, waaruit blijkt dat deze kwetsbaar is.
  • Binnenkomen 1' OR '1'='1: Zorgt ervoor dat de zoekopdracht altijd waar is, zodat alle gebruikers worden geretourneerd.
  • Binnenkomen 1' UNION SELECT user password FROM users--: Voegt zich bij een andere zoekopdracht om verborgen gegevens zoals gebruikersnamen en wachtwoorden op te halen.

2. Gemiddelde beveiliging

De app past basisinvoeropschoning toe met behulp van functies zoalsaddslashes()ontsnappen'.

$id = addslashes($_GET['id']);$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';

Hoe kan een aanval zijn:



Een simpele'injectie zal niet meer werken (omdat het').

Maar aanvallers kunnen het nog steeds omzeilen door numerieke injectie te gebruiken (omdat getallen geen aanhalingstekens nodig hebben).
Voorbeeld:

'metselaarsformule'
1 OR 1=1

Hiermee worden nog steeds alle records geretourneerd.

3. Hoge beveiliging

De app maakt gebruik van voorbereide instructies (geparametriseerde zoekopdrachten) om gebruikersinvoer veilig te verwerken.

$stmt = $pdo->prepare('SELECT first_name last_name FROM users WHERE user_id = ?');$stmt->execute([$id]);

Aanval:

Pogingen als' OR 1=1ofUNION SELECTwerken niet meer.

De query behandelt alle invoer als gegevens en niet als SQL-code.

Soorten SQL-injectie

Er zijn verschillende soorten SQL-injectie

1. Op fouten gebaseerde SQL-injectie

Op fouten gebaseerde SQL-injectie is een type in-band SQL-injectie waarbij een aanvaller er opzettelijk voor zorgt dat de database een foutmelding genereert. De aanvaller analyseert vervolgens dit foutbericht om waardevolle informatie te verkrijgen over de structuur van de database, zoals tabelnamen en kolomnamen, die kan worden gebruikt om verdere, nauwkeurigere aanvallen uit te voeren.

Hoe het werkt

Deze aanval is gericht op applicaties die ruwe databasefouten onthullen in plaats van algemene berichten weer te geven. Door kwaadaardige invoer te injecteren die de SQL-syntaxis verbreekt, activeren aanvallers deze fouten en verkrijgen ze waardevolle aanwijzingen over de databasestructuur.

weer shell
  1. Identificeer een kwetsbare invoer: De aanvaller vindt een invoerveld zoals een zoekbalk of een URL-parameter die rechtstreeks met de database communiceert zonder de juiste invoeropschoning.
  2. Een schadelijke lading injecteren: De aanvaller injecteert een speciaal teken (zoals een enkel aanhalingsteken') of een functie waarvan bekend is dat deze een databasefout veroorzaakt.
  3. Analyseer de fout: De database kan de verkeerd opgestelde query niet verwerken en retourneert een gedetailleerd foutbericht. Dit bericht kan cruciale informatie onthullen, zoals:
    • Het databasesysteem (bijvoorbeeld MySQL Oracle SQL Server).
    • De versie van de database.
    • De volledige SQL-query wordt uitgevoerd.
    • Specifieke syntaxisfouten die kunnen worden gebruikt om tabel- of kolomnamen te begrijpen.
  4. Verfijn de aanval: Met behulp van de informatie die uit het foutbericht is verzameld, kan de aanvaller zijn payload verfijnen om meer gegevens zoals gebruikersnamen en wachtwoorden te extraheren.

Voorbeeld:

Stap 1: Stel uw omgeving in

  • Start DVWA. Het is meestal toegankelijk door naar een URL zoalshttp://localhost/dvwain uw browser.
bestand' loading='lazy' title=
  • Meld u aan bij DVWA met de standaardgegevens:admin/password.
bestand' loading='lazy' title=
  • Ga naar het tabblad DVWA-beveiliging en stel het beveiligingsniveau in op laag. Dit zorgt ervoor dat de kwetsbaarheden gemakkelijk te misbruiken zijn.
bestand' loading='lazy' title=

Stap 2: Identificeer de kwetsbaarheid

De SQL-injectiepagina heeft een eenvoudig invoervak ​​waarin u een gebruikers-ID kunt invoeren. De backend-query is waarschijnlijk zoiets alsSELECT * FROM users WHERE id = 'user_input'

  • Voer een geldig ID in, zoals1in het invoervak ​​en klik op 'Verzenden'. U zou de details van de gebruiker met ID 1 moeten zien.
bestand' loading='lazy' title=

SQL-injectiebron

PHP
 $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( '
' . ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ode ?>
  • Probeer nu de query te verbreken. Voer één citaat in'in het invoervak ​​en verzend.
bestand' loading='lazy' title=

De vraag wordt:

SELECT * FROM users WHERE id = ''';

Hier ziet de database een extra citaat en weet niet hoe de zoekopdracht moet worden voltooid.

kandidaat sleutel

In plaats van u de gebruikersgegevens te tonen, retourneert de applicatie een SQL-fout (zoiets als 'U heeft een fout in uw SQL-syntaxis...')

Dit wordt Error-Based SQL Injection genoemd omdat:

  • De aanvaller verzendt ongeldige invoer (')
  • De database genereert een fout
  • Die fout lekt nuttige informatie over de database (zoals het type DB-nummer van de kolommenstructuur enz.)

2. Union-gebaseerde SQL-injectie

Union-gebaseerde SQL-injectie is een techniek waarbij aanvallers gebruik maken van deUNIONoperator om de resultaten van twee of meer te combinerenSELECTuitspraken in één resultatenset. Hierdoor kunnen ze informatie uit andere tabellen in de database halen. DeUNIONoperator kan alleen worden gebruikt als:

  • Beide query's hebben hetzelfde aantal kolommen
  • De kolommen hebben vergelijkbare gegevenstypen
  • De kolommen staan ​​in dezelfde volgorde

UNION-operator : DeUNIONoperator wordt gebruikt om de resultatenset van twee of meer te combinerenSELECTverklaringen.

  • ElkSELECTverklaring binnenUNIONmoet hetzelfde aantal kolommen hebben
  • De kolommen moeten vergelijkbare gegevenstypen hebben
  • De kolommen moeten in dezelfde volgorde staan
SELECT column_name(s) FROM table1UNIONSELECT column_name(s) FROM table2

Voorbeeld:

Stap 1: Eerst moeten we het aantal kolommen van de bestaande tabel op de website vinden om op UNION gebaseerde SQL-injectie te injecteren:

De SQL-injectiepagina heeft een eenvoudig invoervak ​​waarin u een gebruikers-ID kunt invoeren. De backend-query is waarschijnlijk zoiets als

 SELECT * FROM users WHERE id = 'user_input'

Probeer nu de query te verbreken. Voer één citaat in'in het invoervak ​​en verzend.

Als de applicatie kwetsbaar is, krijgt u een gedetailleerde foutmelding. Het zou er ongeveer zo uit kunnen zien:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1

Stap 2: Gebruik deUNIONTrefwoord om het aantal kolommen te ontdekken

Om deUNIONtrefwoord (een veel voorkomende volgende stap) moet u het aantal kolommen in de oorspronkelijke zoekopdracht weten. U kunt dit achterhalen door gebruik te maken van deORDER BYclausule

naam stad in de VS
  • Probeer de resultaten per kolom te sorteren
1: 1 ORDER BY 1. 
  • Indienen. Het zou moeten werken.
bestand' loading='lazy' title=

SQL-injectiebron

PHP
 if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( '
' . ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ?>
  • Verhoog het getal:
 1 ORDER BY 2. 

Indienen. Het zou moeten werken.

bestand' loading='lazy' title=
  • Blijf verhogen totdat u een foutmelding krijgt. Bijvoorbeeld1 ORDER BY 4zou je kunnen geven:Unknown column '4' in 'order clause'
  • Dit betekent dat de query 3 kolommen heeft.

3. Blindgebaseerde SQL-injectie

Blinde SQL-injectie treedt op wanneer aanvallers de queryresultaten niet rechtstreeks op de webpagina kunnen zien. In plaats daarvan leiden ze informatie af uit subtiele veranderingen in het gedrag of de responstijd van de applicatie. Hoewel het langzamer en vervelender is dan klassieke SQLi, kan het even effectief zijn.

In plaats van gegevens terug te krijgen, leidt de aanvaller informatie af door het gedrag van de webpagina te observeren. Dit gebeurt doorgaans op twee manieren:

  1. Booleaanse blinde SQLi: De aanvaller injecteert een SQL-query die een WAAR of vals resultaat. Het antwoord van de webtoepassing verandert op basis van het feit of de query waar of onwaar is. De pagina kan bijvoorbeeld een ander bericht weergeven of een andere lay-out weergeven.
  2. Op tijd gebaseerde blinde SQLi: De aanvaller injecteert een SQL-query die ervoor zorgt dat de database een tijdrovende actie uitvoert (zoals eenSLEEP()functie) als aan een voorwaarde is voldaan. De aanvaller observeert de tijd die nodig is om de pagina te laden om te bepalen of de geïnjecteerde voorwaarde waar of onwaar was.

Voorbeeld:

Stel je een inlogpagina voor waar je een gebruikersnaam en wachtwoord invoert. De applicatie bouwt een SQL-query als volgt op:

SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input'

Een blinde SQL-injectie zou het manipuleren van deuser_inputveld om de database een vraag te stellen.

In plaats van een directe reactie te krijgen, kan de aanvaller iets als dit proberen:

user_input = 'admin' AND 1=1; --

Als de pagina normaal laadt, weet de aanvaller dat1=1is een WAAR stelling.

user_input = 'admin' AND 1=2; --

Als de pagina een fout vertoont of zich anders gedraagt, weet de aanvaller dat1=2is een vals stelling.

bestand' loading='lazy' title=

Door een reeks van deze waar/onwaar-vragen te gebruiken, kan een aanvaller systematisch karakter voor karakter raden en informatie eruit halen. Het proces kan worden geautomatiseerd om alles te raden, van tabelnamen tot gebruikerswachtwoorden.

Impact van SQL-injectieaanvallen

  • Ongeautoriseerde toegang tot gevoelige gegevens : Aanvallers kunnen persoonlijke financiële of vertrouwelijke informatie ophalen die in de database is opgeslagen.
  • Problemen met de gegevensintegriteit : Aanvallers kunnen kritieke gegevens wijzigen, verwijderen of beschadigen, wat van invloed is op de functionaliteit van de applicatie.
  • Escalatie van privileges : Aanvallers kunnen authenticatiemechanismen omzeilen en beheerdersrechten verkrijgen.
  • Serviceonderbreking : SQL-injectie kan de server overbelasten, wat prestatieverlies of systeemcrashes veroorzaakt.
  • Reputatieschade : Een succesvolle aanval kan de reputatie van een organisatie ernstig schaden, wat kan leiden tot verlies van klantvertrouwen.

SQL-injectieaanvallen voorkomen

Er zijn verschillende best practices om SQL-injectieaanvallen te voorkomen:

1. Gebruik voorbereide verklaringen en geparametriseerde zoekopdrachten

Opgestelde instructies en geparametriseerde query's zorgen ervoor dat gebruikersinvoer als gegevens wordt behandeld en niet als onderdeel van de SQL-query. Deze aanpak elimineert het risico van SQL-injectie.

eenvoudige datumformatter in Java

Voorbeeld in PHP (met MySQLi):

$stmt = $conn->prepare('SELECT * FROM users WHERE username = ? AND password = ?'); $stmt->bind_param('ss' $username $password); $stmt->execute();

2. Gebruik opgeslagen procedures

Opgeslagen procedures zijn vooraf gedefinieerde SQL-query's die in de database zijn opgeslagen. Deze procedures kunnen SQL-injectie helpen voorkomen, omdat ze geen dynamische SQL-query's construeren.

Voorbeeld:

CREATE PROCEDURE GetUserByUsername (IN username VARCHAR(50)) BEGIN SELECT * FROM users WHERE username = username; END;

3. Validatie van invoer op de witte lijst

Zorg ervoor dat gebruikersinvoer wordt gevalideerd voordat deze in SQL-query's wordt gebruikt. Sta alleen bepaalde tekens en patronen toe, zoals alfanumerieke invoer voor velden zoals gebruikersnamen of e-mailadressen.

4. Gebruik ORM-frameworks

Object-Relational Mapping (ORM)-frameworks zoals Overwinteren of Entiteitsframework kan SQL-injectie helpen voorkomen door het automatisch genereren van query's af te handelen, waardoor dynamische queryconstructie wordt voorkomen.

5. Beperk databaserechten

Verleen de minimaal vereiste databasemachtigingen aan gebruikers. Zorg ervoor dat applicaties alleen noodzakelijke acties kunnen uitvoeren (bijvoorbeeld SELECT INSERT) en beperk rechten zoals DROP TABLE of ALTER.

6. Foutafhandeling

Configureer de database en applicatie zo dat er geen gedetailleerde foutmeldingen aan de gebruiker worden weergegeven. Registreer in plaats daarvan fouten intern en geef generieke foutmeldingen weer aan eindgebruikers.