Direct naar inhoud

Authenticatiecookie met te lange geldigheid

CWE-613CWE-539OWASP A07:2021Bijgewerkt 3 september 20265 min leestijd

Een authenticatiecookie met een vervaldatum van maanden houdt de gebruiker ingelogd, maar geeft een aanvaller die het token bemachtigt evenveel tijd. Comfort en risico lopen hier recht tegen elkaar in. De oplossing is niet een korte sessie afdwingen, maar de lange geldigheid verplaatsen naar een apart, intrekbaar en aan het apparaat gebonden token.

“Onthoud mij” is een van de meest gewaardeerde functies in elke applicatie, en tegelijk een van de plaatsen waar beveiliging het stilst wordt weggegeven. Een vinkje dat de gebruiker maanden ingelogd houdt, houdt namelijk ook een aanvaller maanden ingelogd. In dit artikel leest u hoe u het comfort behoudt zonder die prijs te betalen.

Hoe lang mag een authenticatiecookie geldig zijn?

Een authenticatiecookie draagt het bewijs dat iemand is ingelogd. De vervaldatum bepaalt hoe lang dat bewijs meegaat. Een te lange geldigheid betekent dat het token nog steeds toegang geeft lang nadat de oorspronkelijke inlogpoging is vergeten, soms maanden, soms zonder enige bovengrens.

De afweging is oprecht lastig, want beide kanten zijn reëel. Een korte geldigheid dwingt gebruikers voortdurend opnieuw in te loggen, wat leidt tot zwakkere wachtwoorden, opgeslagen inloggegevens en irritatie. Een lange geldigheid is comfortabel, maar verlengt precies de periode waarin een gestolen token bruikbaar blijft.

Denk aan het verschil tussen een dagpas en een sleutel die u voor onbepaalde tijd meegeeft. Beide geven toegang; alleen bij de tweede blijft dat zo, ook nadat u vergeten bent dat u hem hebt uitgegeven.

Hoe wordt een te lang geldig authenticatiecookie misbruikt?

Kwetsbaar:

app.post('/inloggen', async (req, res) => {
  const gebruiker = await controleerInloggegevens(req.body);
  if (!gebruiker) return res.status(401).send('Onjuiste gegevens');

  req.session.userId = gebruiker.id;

  res.cookie('sid', req.sessionID, {
    httpOnly: true,
    secure: true,
    maxAge: 365 * 24 * 60 * 60 * 1000,   // een jaar
  });
  res.send('Welkom');
});

De sessie zelf is een jaar geldig. Wie het token in handen krijgt, heeft daarmee een jaar toegang. Dat token belandt intussen op meer plaatsen dan de browser van de gebruiker: in back-ups van het profiel, op een gedeelde computer waar niemand meer aan denkt, in een synchronisatiedienst tussen apparaten, of in handen van iemand die de laptop later overneemt. Er is geen tweede controlemoment waarop de applicatie zich afvraagt of deze gebruiker er nog steeds hoort te zijn.

Veilig:

const SESSIE_MAX = 8 * 60 * 60 * 1000;             // 8 uur
const ONTHOUD_MAX = 30 * 24 * 60 * 60 * 1000;      // 30 dagen

app.post('/inloggen', async (req, res) => {
  const gebruiker = await controleerInloggegevens(req.body);
  if (!gebruiker) return res.status(401).send('Onjuiste gegevens');

  req.session.regenerate(async () => {
    req.session.userId = gebruiker.id;
    req.session.gestartOp = Date.now();

    res.cookie('__Host-sid', req.sessionID, {
      httpOnly: true, secure: true, sameSite: 'strict',
      path: '/', maxAge: SESSIE_MAX,
    });

    if (req.body.onthoudMij) {
      // Apart token: alleen goed voor het starten van een nieuwe sessie
      const ruw = randomBytes(32).toString('base64url');
      await onthoudTokens.bewaar({
        gebruikerId: gebruiker.id,
        hash: sha256(ruw),                       // nooit het token zelf opslaan
        verlooptOp: Date.now() + ONTHOUD_MAX,
        apparaat: req.get('user-agent'),
      });
      res.cookie('__Host-onthoud', ruw, {
        httpOnly: true, secure: true, sameSite: 'strict',
        path: '/', maxAge: ONTHOUD_MAX,
      });
    }
    res.send('Welkom');
  });
});

De sessie is nu kort en de lange geldigheid zit in een apart token met een eigen rol. Dat token geeft geen directe toegang: het levert hooguit een nieuwe sessie op. Het is opgeslagen als hash, zodat een gelekte database de tokens niet prijsgeeft, het is gekoppeld aan een apparaat en het is intrekbaar. Wordt het gebruikt, dan geeft de server een nieuw token uit en vervalt het oude, biedt iemand daarna het oude token alsnog aan, dan is dat een duidelijk signaal dat er een kopie in omloop is.

Vraag bij gevoelige handelingen altijd opnieuw om het wachtwoord wanneer de sessie is hersteld uit een onthoud-mij-token. De gebruiker heeft dan immers niet aangetoond dat hij het wachtwoord kent; hij heeft alleen aangetoond dat hij een token bezit. Voor het wijzigen van een wachtwoord, een e-mailadres of betaalgegevens is dat te weinig.

Wat is de impact van een te lang geldig authenticatiecookie?

De ernst wordt doorgaans als laag tot middelzwaar beoordeeld, want er is geen directe aanval mogelijk: de aanvaller heeft het token nodig. Wat deze bevinding doet, is de waarde van elk ander lek vergroten.

Een sessietoken kan op veel manieren weglekken, via cross-site scripting, een onversleuteld verzoek, een logbestand, een schermafbeelding of simpelweg een computer die van eigenaar wisselt. Bij een sessie van acht uur is de schade daarvan begrensd. Bij een sessie van een jaar heeft de aanvaller alle tijd: hij kan wachten tot buiten kantooruren, rustig verkennen en op een zelfgekozen moment toeslaan, zonder dat er een tweede inlogpoging nodig is die alarm zou kunnen slaan.

Er speelt ook een organisatorische kant. Bij een lange geldigheid verliest u het overzicht over wie er nog toegang heeft. Medewerkers die zijn vertrokken, apparaten die zijn afgeschreven en accounts waarvan de rechten zijn ingetrokken houden allemaal een geldig token, tenzij u dat actief afdwingt.

Hoe spoor je een te lang geldig authenticatiecookie op?

De vervaldatum van de cookie is direct af te lezen uit de Set-Cookie-header, en dat is het startpunt. Belangrijker is de vraag of die vervaldatum ook iets betekent: een tester verwijdert de vervaldatum uit de cookie en kijkt of het token dan alsnog wordt geaccepteerd. Gebeurt dat, dan wordt de geldigheid alleen door de browser bewaakt en aan serverzijde helemaal niet.

Daarnaast wordt gekeken hoe de onthoud-mij-functie is opgezet. Is het dezelfde sessiecookie met een langere looptijd, of een apart token? Wordt dat token gehasht opgeslagen? Roteert het bij gebruik? Blijft het geldig na een wachtwoordwijziging? En wordt er bij gevoelige handelingen opnieuw om authenticatie gevraagd wanneer de sessie uit zo’n token is hersteld? AssistSec toetst die vragen als geheel, omdat een lange geldigheid met een goed opgezet, intrekbaar en roterend token verdedigbaar is, terwijl dezelfde looptijd op de sessiecookie zelf dat niet is.

Hoe voorkom je een te lang geldig authenticatiecookie?

  • Houd de sessiecookie kort en verplaats een langere geldigheid naar een apart onthoud-mij-token.
  • Bewaak de geldigheid aan serverzijde; vertrouw nooit op de vervaldatum in de cookie alleen.
  • Sla onthoud-mij-tokens gehasht op, zodat een gelekte database geen bruikbare tokens oplevert.
  • Roteer het token bij elk gebruik en trek alles in zodra een verlopen of hergebruikt token wordt aangeboden.
  • Koppel het token aan een apparaat en toon de gebruiker een overzicht van actieve apparaten.
  • Trek alle tokens in bij een wachtwoordwijziging, een rechtenwijziging of het blokkeren van een account.
  • Vraag opnieuw om authenticatie bij gevoelige handelingen binnen een herstelde sessie.
  • Stel de maximale looptijd af op de gevoeligheid van de applicatie en leg die keuze vast in uw beleid.

Bronnen

Veelgestelde vragen

Mag ik gebruikers helemaal niet lang ingelogd houden?

Jawel, maar niet met de sessiecookie zelf. Gebruik daarvoor een apart onthoud-mij-token dat alleen recht geeft op het aanmaken van een nieuwe sessie. Dat token kunt u intrekken, aan een apparaat binden en bij gebruik roteren, terwijl de eigenlijke sessie kort blijft.

Wat is een sessiecookie zonder vervaldatum?

Een cookie zonder Expires of Max-Age wordt door de browser verwijderd zodra die wordt afgesloten. Dat is voor authenticatie meestal de veiligste keuze. Let wel op: veel browsers herstellen bij het opstarten de vorige sessie inclusief cookies, dus reken er niet blind op.

Waarom moet een onthoud-mij-token roteren?

Zodat hergebruik zichtbaar wordt. Geeft u bij elke automatische herkenning een nieuw token uit en wordt een oud token later alsnog aangeboden, dan bestaat er kennelijk een kopie. Dat is het moment om alle tokens van die gebruiker in te trekken en hem te waarschuwen.

Volstaat het om de vervaldatum te verkorten?

Alleen als de server die grens ook zelf bewaakt. De vervaldatum op een cookie is een instructie aan de browser en zegt niets over de geldigheid van het token. Een aanvaller stuurt de waarde gewoon mee na die datum; wordt dat aan serverzijde niet gecontroleerd, dan verandert er niets.

Verwante artikelen

Druk op / om te zoeken · Esc