✦ Oplossingen · Database (MySQL/MariaDB)

SQL-injectie voorkomen met prepared statements

SQL-injectie ontstaat als invoer van bezoekers rechtstreeks in een query komt. Zo voorkom je het in PHP met prepared statements (PDO/mysqli), whitelists en beperkte databaserechten.

Waarom gebeurt dit?

Bij SQL-injectie plakt code de invoer van een bezoeker (uit een formulier of URL) direct in een SQL-opdracht. Een kwaadwillende kan dan zelf SQL meegeven en zo gegevens uitlezen, wijzigen of verwijderen. Het is al jaren een van de bekendste kwetsbaarheden van webapplicaties.

De oplossing is structureel en goed bekend: invoer nooit als SQL-tekst behandelen, maar als waarde doorgeven via prepared statements. Escapen met de hand is foutgevoelig en geen vervanging.

Zo los je het op, stap voor stap

Menunamen kunnen per versie of toestel iets anders heten. Loop de stappen op volgorde af en stop zodra het werkt.

  1. Herken de gevaarlijke vorm

    Elke query waarin een variabele uit $_GET, $_POST, $_COOKIE of een andere externe bron in de SQL-tekst wordt geplakt, is verdacht.

    <?php
    // ONVEILIG
    $sql = "SELECT * FROM klanten WHERE email = '" . $_POST['email'] . "'";
  2. Gebruik prepared statements met PDO

    De query en de waarden gaan apart naar de server; de waarde kan de query niet meer veranderen.

    <?php
    $stmt = $pdo->prepare('SELECT * FROM klanten WHERE email = ?');
    $stmt->execute([$_POST['email'] ?? '']);
    $klant = $stmt->fetch();
  3. Of met mysqli

    Met mysqli geef je bij bind_param het type van elke waarde op (i = getal, s = tekst).

    <?php
    $stmt = $db->prepare('SELECT naam FROM klanten WHERE id = ?');
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $resultaat = $stmt->get_result();
  4. Gebruik een whitelist voor kolom- en tabelnamen

    Placeholders werken alleen voor waarden, niet voor namen of sorteerrichting. Laat die alleen uit een vaste lijst komen.

    <?php
    $toegestaan = ['naam', 'aangemaakt', 'plaats'];
    $kolom = in_array($_GET['sort'] ?? '', $toegestaan, true) ? $_GET['sort'] : 'naam';
    $sql = "SELECT * FROM klanten ORDER BY $kolom";
  5. Geef de databasegebruiker minimale rechten

    De gebruiker van de website heeft geen rechten nodig op andere databases of op beheertaken. Zo is de schade beperkt als er toch iets misgaat.

  6. In WordPress: $wpdb->prepare()

    Gebruik in eigen WordPress-code altijd $wpdb->prepare() voor queries met variabelen.

    <?php
    $rij = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}aanvragen WHERE id = %d", $id
    ) );

Lukt het niet? Wij helpen

Kom je er met deze stappen niet uit, of wil je het liever niet zelf doen? We kijken online mee of komen langs. Hulp op afstand kost €20 per uur; komen we langs, dan is de prijs op aanvraag. Je weet vooraf waar je aan toe bent.

Aanvraag

Hulp aanvragen

Schrijf kort wat er misgaat en wat je al hebt geprobeerd. Kies of we bellen, online meekijken of langskomen.

Veelgestelde vragen

Vragen over dit probleem

Is mysqli_real_escape_string genoeg?

Het helpt als je het overal correct gebruikt, met de juiste tekenset en aanhalingstekens. Prepared statements zijn eenvoudiger en veiliger, omdat je het niet kúnt vergeten.

Mijn site gebruikt een framework. Ben ik dan veilig?

Query builders en ORM's gebruiken prepared statements, zolang je geen ruwe SQL met geplakte invoer schrijft. Controleer vooral de plekken met 'raw'-queries.

Hoe weet ik of mijn site kwetsbaar is?

Zoek in de code naar queries waarin variabelen worden geplakt, en laat een beveiligingscontrole doen. Test nooit op andermans site.