Een Race Condition (race-omstandigheid) is een logische kwetsbaarheid die optreedt wanneer een applicatie afhankelijk is van de volgorde of timing van processen die gelijktijdig worden uitgevoerd. Binnen WooCommerce-webshops vormt dit een subtiel maar serieus financieel risico. Aanvallers kunnen dit mechanisme misbruiken door honderden gelijktijdige verzoeken te sturen om een eenmalige kortingscode meerdere keren te gebruiken, of om producten te bestellen die eigenlijk al zijn uitverkocht.

Het mechanisme van een e-commerce Race Condition

Stel dat een WooCommerce-winkel een kortingscode heeft die strikt "maximaal 1 keer per klant" gebruikt mag worden. Wanneer een klant de code toepast en op de knop "Bestelling plaatsen" klikt, voert de server de volgende stappen sequentieel uit:

  1. Controleer in de database of de klant deze code al heeft gebruikt.

  2. Indien niet gebruikt: bereken het nieuwe orderbedrag.

  3. Verwerk de betaling.

  4. Werk de database bij en registreer dat deze klant de code heeft verbruikt.

Het probleem ontstaat in de fractie van een seconde tussen stap 1 en stap 4. Als een aanvaller met behulp van een script (bijvoorbeeld via geautomatiseerde HTTP-verzoeken) 50 verzoeken exact tegelijkertijd naar de server stuurt, kan het gebeuren dat voor alle 50 verzoeken stap 1 succesvol wordt doorlopen voordat de eerste update in stap 4 is verwerkt. De server ziet 50 keer dat de code "nog niet is gebruikt" en past de korting 50 keer toe op parallelle bestellingen.

Gevaren voor voorraadbeheer

Hetzelfde principe geldt voor producten met een beperkte voorraad. Als er nog één high-end artikel op voorraad is, en tien aanvallers sturen tegelijkertijd een aankoopverzoek, kan de server de voorraadstatus onjuist valideren. Dit leidt tot overselling, administratieve problemen en potentiële financiële claims van klanten.

Hoe ontwikkelaars Race Conditions voorkomen

Het voorkomen van race conditions vereist het implementeren van zogenaamde database locks (databasovergrendelingen) of atomaire operaties. Ontwikkelaars moeten ervoor zorgen dat een specifieke rij in de database tijdelijk wordt vergrendeld voor andere processen totdat de huidige transactie volledig is afgerond.

In PHP en WordPress kan dit worden bereikt door gebruik te maken van de FOR UPDATE clausule in SQL-queries via de $wpdb klasse, of door het implementeren van een transient-gebaseerd vergrendelingsmechanisme:

PHP
 
$lock_key = 'coupon_lock_' . get_current_user_id();

// Probeer een unieke vergrendeling te claimen voor 5 seconden
if (false === get_transient($lock_key)) {
    set_transient($lock_key, 'locked', 5);
    
    // Voer hier de coupon-validatie en database-update uit...
    
    // Verwijder de vergrendeling na afloop
    delete_transient($lock_key);
} else {
    // Verzoek is te snel achter elkaar verstuurd, weiger de transactie
    wp_die('Systeembericht: Gelijktijdige transactie gedetecteerd. Probeer het opnieuw.');
}

Advies voor site-eigenaren

  • Gebruik Object Caching: Systemen zoals Redis ondersteunen zeer snelle atomaire operaties die cruciaal zijn voor het effectief vergrendelen van gelijktijdige processen.

  • Monitoor couponmisbruik: Gebruik geautomatiseerde rapportages om direct een melding te ontvangen wanneer een unieke couponcode binnen een tijdsbestek van enkele seconden meerdere keren door dezelfde gebruiker wordt geregistreerd.