Direct naar inhoud

Gedetailleerde foutmeldingen

CWE-209CWE-200OWASP A05:2021Bijgewerkt 3 september 20265 min leestijd

Een foutmelding met een stacktrace, een databasequery of een bestandspad vertelt een aanvaller hoe uw applicatie is opgebouwd. Die informatie bespaart hem het verkennende werk en maakt gerichte vervolgaanvallen mogelijk. Gebruikers hebben aan een neutrale melding met een referentienummer genoeg; de details horen in uw eigen logbestanden.

Een foutmelding is geschreven om een ontwikkelaar te helpen, en dat doet ze goed: ze vertelt precies wat er misging, waar in de code, met welke gegevens. Belandt diezelfde melding bij een bezoeker, dan helpt ze een aanvaller even doeltreffend. Hieronder leest u wat er zoal in staat, wat een aanvaller ermee doet en hoe u fouten afhandelt zonder uw ontwikkelaars blind te maken.

Wat zijn gedetailleerde foutmeldingen?

Van gedetailleerde foutmeldingen spreken we wanneer een applicatie bij een onverwachte situatie technische informatie toont die bedoeld is voor de ontwikkelaar. In de praktijk gaat het om een stacktrace met bestandspaden en regelnummers, de SQL-query die faalde, de versie van het framework of de databaseserver, of de inhoud van variabelen op het moment van de fout.

Het punt is niet dat één zo’n melding meteen tot compromittering leidt. Het punt is dat een aanvaller zijn werk begint met verkennen: welke techniek draait hier, welke versies, hoe is de code georganiseerd, hoe zien de queries eruit. Een gedetailleerde foutmelding levert die informatie in één keer, zonder dat hij ernaar hoeft te zoeken.

Vergelijk het met een gebouw waar op de deur van de meterkast een schema hangt van de complete elektrische installatie. Voor de monteur is dat handig. Voor wie kwaad wil, is het de plattegrond die hij anders had moeten reconstrueren.

Wat staat er in zo’n foutmelding?

Kwetsbaar:

app.get('/factuur/:id', async (req, res) => {
  try {
    const factuur = await db.query(
      'SELECT * FROM facturen WHERE id = ? AND klant_id = ?',
      [req.params.id, req.gebruiker.klantId],
    );
    res.json(factuur);
  } catch (fout) {
    res.status(500).send(fout.stack);      // alles naar de gebruiker
  }
});

Een verzoek met een onverwachte waarde levert dan zoiets op:

Error: ER_PARSE_ERROR: You have an error in your SQL syntax near ''' AND klant_id = 4471'
    at Query.Sequence._packetToError (/opt/portaal/node_modules/mysql/lib/...)
    at /opt/portaal/src/facturen/repository.js:88:19
    at FactuurService.zoek (/opt/portaal/src/facturen/service.js:34:7)

In vier regels staat een aanzienlijke hoeveelheid informatie. De database is MySQL. De applicatie draait in /opt/portaal. De code is opgedeeld in een repository- en een servicelaag. Er is een kolom klant_id, en de waarde daarvan voor deze gebruiker is 4471. En, het belangrijkste: de invoer belandt kennelijk zó in de query dat een enkel aanhalingsteken hem laat breken: een sterke aanwijzing voor SQL-injectie. Wat een aanvaller anders met tientallen blinde pogingen had moeten vaststellen, staat hier zwart op wit.

Veilig:

app.get('/factuur/:id', async (req, res, next) => {
  const factuur = await facturen.zoek(req.params.id, req.gebruiker.klantId)
    .catch(next);
  if (!factuur) return res.status(404).json({ fout: 'Niet gevonden' });
  res.json(factuur);
});

// Eén centrale afhandeling voor alles wat misgaat
app.use((fout, req, res, next) => {
  const referentie = randomUUID();

  logger.error({                       // volledige details, alleen intern
    referentie,
    bericht: fout.message,
    stack: fout.stack,
    pad: req.originalUrl,
    gebruiker: req.gebruiker?.id,
  });

  res.status(500).json({
    fout: 'Er is iets misgegaan. Neem contact op met onze helpdesk.',
    referentie,                        // koppelt de melding aan het logboek
  });
});

De gebruiker krijgt een bruikbare maar nietszeggende melding met een referentienummer. De ontwikkelaar verliest niets: de volledige stacktrace, het pad en de gebruiker staan in het logboek, gekoppeld aan datzelfde nummer. Belt iemand de helpdesk met de referentie, dan is het incident in één zoekopdracht terug te vinden.

Denk ook aan de foutpagina’s die uw webserver of framework zelf genereert bij een situatie die uw code nooit bereikt: een niet-bestaande route, een te grote upload, een verkeerd gevormd verzoek. Die vallen buiten uw eigen afhandeling en tonen standaard vaak wél versie-informatie of een stacktrace.

Wat is de impact van gedetailleerde foutmeldingen?

De ernst is doorgaans laag tot middelzwaar, omdat het lekken van informatie op zichzelf geen toegang oplevert. De betekenis ligt in de versnelling die het een aanvaller geeft.

Een aanvaller die uw framework, de versies en de structuur van uw code kent, kan gericht zoeken naar bekende kwetsbaarheden in die specifieke versies in plaats van breed te proberen. Interne bestandspaden zijn bruikbaar bij aanvallen als path traversal of bij het uploaden van bestanden. Ook een databasefout die de query prijsgeeft, verkort het uitbuiten van SQL-injectie van een tijdrovend blind proces tot een kwestie van minuten.

Er is ook een scenario waarin de foutmelding zelf al de schade is. Bevat de uitzondering de inhoud van variabelen, dan kunnen daar persoonsgegevens, tokens of inloggegevens voor een externe dienst in staan. Dat gebeurt vaker dan gedacht bij fouten in de communicatie met een andere API, waar de volledige aanvraag inclusief de gebruikte sleutel in de melding terechtkomt.

Hoe spoor je gedetailleerde foutmeldingen op?

Een tester lokt fouten uit op plaatsen waar de applicatie invoer verwerkt: een letter waar een getal wordt verwacht, een aanhalingsteken in een tekstveld, een te lange waarde, een ontbrekende parameter, een verkeerd gevormd JSON-verzoek. Vervolgens wordt gekeken wat er terugkomt.

Daarnaast worden de randen van de applicatie afgelopen: niet-bestaande paden, verkeerde HTTP-methodes, uploads boven de limiet en verzoeken met onverwachte headers. Juist daar reageert vaak de webserver of het framework in plaats van uw eigen code, met een standaardpagina die meer prijsgeeft. Ook wordt gecontroleerd of de API dezelfde discipline hanteert als de webinterface, en of er ergens een debugmodus aanstaat die uitgebreide informatie toont. AssistSec kijkt daarbij ook naar het verschil tussen antwoorden: twee neutrale meldingen die net iets van elkaar afwijken, kunnen samen alsnog verraden welke accounts of records bestaan.

Hoe voorkom je gedetailleerde foutmeldingen?

  • Vang fouten centraal af en geef gebruikers een neutrale melding met een uniek referentienummer.
  • Schrijf de volledige details (stacktrace, query, context) uitsluitend naar uw eigen logbestanden.
  • Schakel debug- en ontwikkelmodus uit in elke omgeving die vanaf internet bereikbaar is.
  • Configureer ook de standaard foutpagina’s van uw webserver en framework, niet alleen die van uw eigen code.
  • Toon geen versie-informatie van uw framework, server of database in foutmeldingen of headers.
  • Zorg dat API’s een gestructureerd, neutraal foutobject teruggeven zonder onderliggende uitzondering.
  • Filter gevoelige waarden uit uw logbestanden, zodat tokens en persoonsgegevens er niet in belanden.
  • Houd meldingen die van elkaar kunnen verschillen gelijk, zodat ze geen bestaande accounts of records verraden.
  • Test bewust op foutsituaties als onderdeel van uw acceptatieproces, niet alleen op het gelukkige pad.

Bronnen

Veelgestelde vragen

Mag ik in een testomgeving wel volledige fouten tonen?

Ja, en dat is ook praktisch. De valkuil is dat testomgevingen vaak bereikbaar zijn vanaf internet en dezelfde structuur hebben als productie. Zorg dan dat die omgeving is afgeschermd, want een stacktrace uit acceptatie verraadt vrijwel hetzelfde als een uit productie.

Wat moet ik de gebruiker dan tonen?

Een korte, neutrale melding dat er iets is misgegaan, met een uniek referentienummer. Dat nummer koppelt u in uw eigen logbestanden aan de volledige details. De gebruiker kan het doorgeven aan uw helpdesk, en u hoeft niets prijs te geven over de oorzaak.

Is een foutmelding zonder stacktrace veilig?

Niet automatisch. Ook de tekst zelf kan verraden wat er misging: een melding over een dubbele sleutel bevestigt dat een record bestaat, en een verschil tussen twee meldingen kan gebruikersnamen of geldige identificaties blootleggen. Let op wat het verschil tussen twee antwoorden vertelt.

Hoe zit het met foutmeldingen uit een API?

Daar gelden dezelfde regels, en er wordt vaker tegen gezondigd omdat men aanneemt dat alleen de eigen frontend meekijkt. Geef een gestructureerd, neutraal foutobject terug met een code en een referentie, en nooit de onderliggende uitzondering of query.

Verwante artikelen

Druk op / om te zoeken · Esc