Direct naar inhoud

Sessie blijft geldig na verwijderen van een account

CWE-613CWE-285OWASP A01:2021Bijgewerkt 3 september 20265 min leestijd

Wordt een account geblokkeerd of verwijderd terwijl de gebruiker is ingelogd, dan blijft de bestaande sessie in veel applicaties gewoon werken. De autorisatiecontrole kijkt naar de sessie en niet naar de actuele status van het account. Een vertrokken medewerker of een gedeactiveerde aanvaller houdt zo toegang tot de eerstvolgende keer dat de sessie verloopt.

Het blokkeren van een account voelt als een definitieve handeling: de knop is omgezet, de toegang is ingetrokken. Voor wie op dat moment níet is ingelogd, klopt dat. Voor wie wél een actieve sessie heeft, verandert er in veel applicaties helemaal niets. Hieronder leest u hoe dat komt en waarom het een toegangscontroleprobleem is en geen sessieprobleem.

Wat gaat er mis bij het verwijderen van een account?

Bij het inloggen stelt de applicatie vast wie iemand is en of hij toegang mag hebben. Die uitkomst wordt vastgelegd in de sessie. Bij elk volgend verzoek wordt vervolgens alleen nog de sessie geraadpleegd: staat daar een gebruikersnummer in, dan is de gebruiker ingelogd.

Blijft de sessie geldig na het verwijderen van een account, dan is die redenering nooit onderbroken. De applicatie vraagt zich bij het tweede en elk volgend verzoek niet meer af of dit account nog bestaat, nog actief is en nog dezelfde rechten heeft. Ze vertrouwt op een beslissing die op een eerder moment is genomen.

Denk aan een bezoekerspas die bij binnenkomst wordt gecontroleerd en daarna niet meer. Wordt de bezoeker onderweg de toegang ontzegd, dan hoort dat bij de deuren bekend te zijn. Bij een systeem dat alleen bij de ingang controleert, loopt hij gewoon door.

Hoe wordt een sessie die een verwijderd account overleeft misbruikt?

Kwetsbaar:

// De sessie is de enige bron van waarheid
function huidigeGebruiker(req) {
  if (!req.session.userId) return null;
  return {
    id: req.session.userId,
    rol: req.session.rol,          // vastgelegd bij het inloggen
  };
}

app.delete('/beheer/gebruikers/:id', async (req, res) => {
  await gebruikers.verwijder(req.params.id);
  res.send('Gebruiker verwijderd');   // sessies blijven ongemoeid
});

De beheerder verwijdert het account en krijgt een bevestiging. In de gebruikerstabel is de regel weg, in het overzicht verschijnt de naam niet meer. Al de sessie van die gebruiker bestaat nog, met het gebruikersnummer en de rol erin. Zijn volgende verzoek verloopt zonder enige hindernis:

GET /dossiers/exporteer HTTP/1.1
Host: portaal.example
Cookie: sid=8f42c19ade7b3f5c

HTTP/1.1 200 OK

De gebruiker bestaat niet meer en heeft nog steeds toegang. Bij een medewerker die op staande voet is vertrokken, is dat precies het venster waarin de meeste schade wordt aangericht.

Veilig:

// Bij elk verzoek wordt de actuele status opgehaald
async function huidigeGebruiker(req) {
  if (!req.session.userId) return null;

  const gebruiker = await gebruikers.zoek(req.session.userId);
  if (!gebruiker || gebruiker.status !== 'actief') {
    await req.session.destroy();
    return null;
  }
  return gebruiker;                  // inclusief de rechten van dit moment
}

app.delete('/beheer/gebruikers/:id', async (req, res) => {
  await gebruikers.blokkeer(req.params.id);
  await sessies.verwijderVoorGebruiker(req.params.id);   // actief opruimen
  await tokens.trekIn(req.params.id);
  await auditlog.schrijf('account geblokkeerd', { door: req.gebruiker.id });
  res.send('Gebruiker geblokkeerd en sessies beëindigd');
});

Er gebeuren nu twee dingen die elkaar aanvullen. De autorisatiecontrole raadpleegt bij elk verzoek de actuele status in plaats van de opgeslagen momentopname, waardoor ook rechten die tussentijds zijn gewijzigd meteen gelden. En bij het blokkeren worden de bestaande sessies en tokens actief opgeruimd, zodat de toegang direct eindigt in plaats van bij het volgende verzoek.

Let op de volgorde bij het verwijderen van accounts. Wordt de gebruikersrecord verwijderd terwijl de sessie blijft bestaan, dan kan de applicatie in een onvoorspelbare toestand terechtkomen: sommige controles falen open in plaats van dicht, bijvoorbeeld wanneer een ontbrekende rol wordt behandeld als “geen beperkingen”. Ruim daarom altijd eerst de sessies op.

Wat is de impact van een sessie die een verwijderd account overleeft?

De ernst loopt van middelzwaar tot hoog, en dat hangt af van wie er wordt geblokkeerd en waarom. Gaat het om een routinematige opschoning van een inactief account, dan is het effect gering. Gaat het om een gedwongen vertrek, een vermoeden van fraude of een gecompromitteerd account, dan is dit het moment waarop de maatregel juist moet werken.

Het scenario dat het meest voorkomt is een vertrekkende medewerker. HR meldt het vertrek, de beheerder blokkeert het account, en het proces wordt als afgerond beschouwd. Blijft de sessie op de laptop van die medewerker geldig, dan heeft hij nog uren of dagen toegang tot klantgegevens, documenten en systemen, precies in de periode waarin de organisatie denkt dat de toegang is ingetrokken.

Nog vervelender is het tweede scenario: een account is gecompromitteerd, dit wordt ontdekt en het account wordt geblokkeerd als eerste incidentmaatregel. Houdt de aanvaller zijn sessie, dan is de reactie op het incident feitelijk mislukt terwijl iedereen denkt dat het probleem is ingedamd. Dat maakt deze bevinding niet alleen een technisch, maar ook een organisatorisch risico: het verstoort het vertrouwen in de eigen maatregelen.

Hoe spoor je een sessie die een verwijderd account overleeft op?

De test vraagt twee accounts. Een tester logt in als de doelgebruiker, laat die sessie openstaan en blokkeert of verwijdert het account vanuit een beheerdersaccount. Vervolgens wordt met de eerste sessie een verzoek naar een beschermde route gestuurd. Werkt dat nog, dan is de bevinding aangetoond.

Dezelfde opzet wordt herhaald voor varianten die vaak apart zijn geïmplementeerd: het intrekken van een rol, het wijzigen van een groepslidmaatschap, het uitschakelen van een account in een centrale directory en het verlopen van een licentie of abonnement. In de praktijk blijkt regelmatig dat het blokkeren wél werkt, maar het intrekken van rechten niet, of andersom. Ook wordt gekeken of tokens voor API-toegang, mobiele applicaties en integraties worden meegenomen, want die worden bij het opruimen vaak vergeten. AssistSec test daarbij expliciet de tijdspanne: hoe lang blijft de oude situatie gelden, en is dat venster acceptabel voor het soort gegevens dat achter de applicatie zit.

Hoe voorkom je een sessie die een verwijderd account overleeft?

  • Haal de status en de rechten van de gebruiker bij elk verzoek op in plaats van ze in de sessie te bevriezen.
  • Verwijder bij het blokkeren of verwijderen van een account actief alle bijbehorende sessies en tokens.
  • Trek ook API-sleutels, refresh-tokens en koppelingen van mobiele applicaties in.
  • Laat een ontbrekende gebruiker of rol altijd leiden tot weigeren, nooit tot doorlaten.
  • Gebruik een korte cache voor de accountstatus als prestaties een rol spelen, en maak die cache leeg bij een wijziging.
  • Pas dezelfde aanpak toe bij het intrekken van rollen en groepslidmaatschappen, niet alleen bij het blokkeren van het hele account.
  • Ververs bij federatieve authenticatie de status periodiek in plaats van alleen bij het inloggen.
  • Leg blokkades en het beëindigen van sessies vast in een auditlog, zodat achteraf aantoonbaar is wanneer de toegang werkelijk eindigde.

Bronnen

Veelgestelde vragen

Waarom valt dit onder toegangscontrole en niet onder sessiebeheer?

Omdat de kern niet is dat de sessie te lang leeft, maar dat de autorisatiebeslissing op verouderde gegevens berust. De applicatie vertrouwt op wat er bij het inloggen waar was in plaats van op wat er nu waar is. Dat is precies wat gebroken toegangscontrole inhoudt.

Moet ik bij elk verzoek de database raadplegen?

Niet noodzakelijk in ruwe vorm. Een korte cache van enkele seconden tot een minuut is meestal een acceptabel compromis, mits u die cache actief leegmaakt op het moment dat een account wordt geblokkeerd. Zo blijft de prestatie op peil zonder dat de status lang achterloopt.

Geldt dit ook voor het intrekken van rechten?

Ja, en daar gaat het nog vaker mis. Wordt een rol uit de sessie of uit een token gelezen in plaats van bij elk verzoek opgezocht, dan houdt een gebruiker zijn oude rechten tot de sessie verloopt. Bij het intrekken van een beheerdersrol is dat een direct beveiligingsprobleem.

Wat als accounts worden beheerd in een centrale directory?

Dan moet de applicatie de status daar periodiek verversen of op wijzigingen worden geattendeerd. Een koppeling die de status alleen bij het inloggen ophaalt, laat precies dit gat open. Bij federatieve authenticatie is een korte tokengeldigheid daarom extra belangrijk.

Verwante artikelen

Druk op / om te zoeken · Esc