Brute force en credential stuffing
CWE-307OWASP A07:2021Bijgewerkt 31 augustus 20267 min leestijd
Brute force is het systematisch proberen van inloggegevens tot een combinatie werkt; credential stuffing gebruikt daarvoor gebruikersnamen en wachtwoorden die bij een ander bedrijf zijn gelekt. Beide aanvallen slagen alleen als uw applicatie het aantal pogingen niet beperkt. De oplossing is throttling per account en per bron, een verplichte tweede factor en een controle op gelekte wachtwoorden.
Elk inlogformulier dat vanaf internet bereikbaar is, krijgt dagelijks bezoek van geautomatiseerde scripts. Ze raden wachtwoorden, of ze vullen e-mailadressen en wachtwoorden in die bij een ander bedrijf zijn gelekt. Zolang uw applicatie een onbeperkt aantal pogingen accepteert, is binnenkomen vooral een kwestie van tijd en bandbreedte. Hieronder leest u hoe die aanvallen werken en welke maatregelen ze onrendabel maken.
Wat is brute force en credential stuffing?
Brute force is een aanval waarbij iemand systematisch inloggegevens probeert tot een combinatie werkt, doordat de applicatie het aantal pogingen niet beperkt. Credential stuffing is de effectievere variant: de aanvaller raadt niet, maar vult combinaties van e-mailadres en wachtwoord in die bij een ander bedrijf zijn buitgemaakt, in de wetenschap dat een deel van uw gebruikers overal hetzelfde wachtwoord gebruikt. In de CWE-catalogus heet de onderliggende zwakte onvoldoende beperking van het aantal authenticatiepogingen, CWE-307.
Een alledaagse vergelijking: een inbreker die elke sleutel uit een grote bos op uw voordeur probeert, doet aan brute force. Een inbreker die de sleutel van uw fietsenhok heeft gevonden en die zonder verder nadenken op uw voordeur probeert, doet aan credential stuffing. De tweede heeft veel minder pogingen nodig, want hij begint met een sleutel die aantoonbaar van u is.
Daartussen zit password spraying. De aanvaller kiest één veelgebruikt wachtwoord, bijvoorbeeld een seizoen gevolgd door het jaartal, en probeert dat tegen duizenden accounts tegelijk. Per account blijft het bij één poging, dus een teller die alleen per account kijkt, ziet niets ongewoons. Dat is precies de reden waarom een blokkade na vijf mislukte pogingen op één account geen verdediging is tegen deze variant.
Staat er wel een tweede factor tussen, dan verschuift de aanval nog een stap. MFA staat voor multifactorauthenticatie: naast het wachtwoord is een tweede bewijs nodig, bijvoorbeeld een code of een hardwaresleutel. Bij MFA fatigue heeft de aanvaller het wachtwoord al en stuurt hij pushmeldingen tot de gebruiker er uit gewoonte of irritatie één goedkeurt.
Hoe werkt een brute force- of credential stuffing-aanval?
Neem een gewoon inlogformulier. De applicatie zoekt de gebruiker op, vergelijkt het wachtwoord en zet bij succes een sessie. Er is geen teller, geen vertraging en geen limiet per bron.
Kwetsbaar:
app.post("/login", async (req, res) => {
const { email, password } = req.body;
const user = await db.users.findByEmail(email);
if (!user) {
// Twee verschillende meldingen verraden welke adressen bestaan
return res.status(401).send("Onbekend e-mailadres");
}
if (await bcrypt.compare(password, user.passwordHash)) {
req.session.userId = user.id;
return res.redirect("/dashboard");
}
// Geen teller, geen vertraging, geen limiet per bron
return res.status(401).send("Onjuist wachtwoord");
});
De aanvaller neemt één geslaagde aanvraag over uit zijn browser en herhaalt die met een lijst. Bij credential stuffing komt die lijst uit een openbare verzameling gelekte combinaties, bij spraying gaat het om één wachtwoord tegen veel adressen.
POST /login HTTP/1.1
Host: app.example.com
Content-Type: application/x-www-form-urlencoded
email=j.jansen@example.com&password=Zomer2026!
Zo’n verzoek kost enkele milliseconden. Met duizend gelijktijdige verbindingen via residentiële proxy’s zijn honderdduizenden combinaties per uur haalbaar, verdeeld over zoveel IP-adressen dat geen enkel adres opvalt. De twee verschillende foutmeldingen helpen de aanvaller daarbij: “Onbekend e-mailadres” bevestigt welke adressen niet bestaan, zodat hij zijn lijst eerst opschoont en pas daarna wachtwoorden gaat proberen.
De veilige versie doet vier dingen tegelijk. Ze telt pogingen per account en per bron, ze geeft in beide gevallen dezelfde foutmelding, ze besteedt evenveel rekentijd aan een onbekend adres als aan een bestaand adres, en ze behandelt het wachtwoord als de eerste van twee stappen.
Veilig:
const MAX_PER_ACCOUNT = 5; // per 15 minuten
const MAX_PER_SOURCE = 50; // per 15 minuten, per IP-adres
app.post("/login", async (req, res) => {
const { email, password } = req.body;
const account = "acct:" + normaliseEmail(email);
const source = "src:" + clientIp(req);
// Twee onafhankelijke tellers, in een gedeelde store
if (await overLimit(account, MAX_PER_ACCOUNT, 900) ||
await overLimit(source, MAX_PER_SOURCE, 900)) {
return res.status(429).send("Te veel pogingen. Probeer het later opnieuw.");
}
const user = await db.users.findByEmail(email);
// Altijd hashen, ook zonder gevonden gebruiker: gelijke responstijd
const hash = user ? user.passwordHash : DUMMY_HASH;
const ok = (await bcrypt.compare(password, hash)) && Boolean(user);
if (!ok) {
await countFailure(account, source);
// Eén melding voor beide gevallen
return res.status(401).send("E-mailadres of wachtwoord is onjuist.");
}
await resetFailures(account);
// Wachtwoord klopt; de identiteit staat pas vast na de tweede factor
req.session.pendingUserId = user.id;
return res.redirect("/login/mfa");
});
De teller per account remt het raden op één slachtoffer. De teller per bron remt spraying, want die aanval verdeelt zijn pogingen juist over veel accounts en valt per account niet op. Beide zijn nodig: elke teller dekt precies de aanval af die de andere doorlaat. Bewaar de tellers centraal, bijvoorbeeld in Redis, anders telt elke applicatieserver zijn eigen deel en ligt de werkelijke limiet een factor hoger.
Wat is de impact van brute force en credential stuffing?
Eén overgenomen account levert de aanvaller alles op wat die gebruiker mag zien en doen: persoonsgegevens, orders, facturen, interne documenten. Vanuit dat account volgt vaak een tweede stap, want intern verstuurde berichten worden nauwelijks gewantrouwd. Gaat het om een beheerder of een servicedesk-medewerker die wachtwoorden mag resetten, dan reikt de schade tot het hele platform.
Zakelijk vertaalt zich dat naar fraude en terugboekingen, misbruik van opgeslagen betaalgegevens, diefstal van spaarpunten of tegoeden en een mogelijke meldplicht bij de toezichthouder wanneer persoonsgegevens zijn ingezien. De aanval zelf kost bovendien capaciteit: een grootschalige credential stuffing-golf legt authenticatieservers en helpdesks plat, ook als geen enkele poging slaagt.
Omdat de ernst afhangt van het account dat valt en van wat er nog achter zit, loopt de classificatie van middel tot hoog. Een enkel klantaccount met beperkte gegevens en verplichte MFA is beheersbaar. Een systeem zonder tweede factor, waar hetzelfde wachtwoord ook toegang geeft tot VPN of e-mail, zit aan de bovenkant van die schaal.
Hoe spoort u brute force en credential stuffing op?
In de logs is het patroon herkenbaar: een verhouding tussen mislukte en geslaagde aanmeldingen die plotseling omslaat, veel verschillende gebruikersnamen vanaf één bron, of juist één wachtwoordpoging per account verspreid over honderden bronnen. Let ook op uniforme user agents, ongebruikelijke tijdstippen en een piek in wachtwoordresets kort na een bekend datalek elders.
Een tester begint met de vraag of er überhaupt een limiet is, en daarna of die limiet te omzeilen valt. De klassieke gaten: de teller hangt aan de sessiecookie en verdwijnt zodra u die cookie weglaat, de applicatie vertrouwt de header X-Forwarded-For en de aanvaller vult die zelf, of het webformulier is begrensd terwijl /api/login, de mobiele API en een oud protocol als IMAP ongelimiteerd doorlopen. Vergeet de omliggende endpoints niet: wachtwoord vergeten, de verificatie van een eenmalige code en de registratie lekken vaak of een adres bestaat, en een OTP van zes cijfers zonder limiet is in korte tijd uit te proberen.
Scanners zien alleen of een aantal snelle pogingen op de hoofdroute wordt geblokkeerd. Of de limiet ook geldt bij een gedistribueerde, langzame aanval en op elke nevenroute, blijkt pas uit handmatig onderzoek. AssistSec neemt deze controles mee in een penetratietest, inclusief het gedrag van de tweede factor en de foutmeldingen rond gebruikersnamen.
Hoe voorkomt u brute force en credential stuffing?
- Beperk pogingen per account en per bron. Gebruik een oplopende vertraging en een tijdelijke blokkade in plaats van een harde afsluiting, en bewaar de tellers in een gedeelde store zodat ze over alle servers gelden.
- Zet MFA aan, standaard en niet alleen voor beheerders. Geef de voorkeur aan passkeys of een hardwaresleutel; gebruikt u pushmeldingen, zet dan number matching aan en begrens het aantal meldingen.
- Controleer nieuwe wachtwoorden tegen bekende datalekken. Vergelijk lokaal met een lijst van gelekte hashes of gebruik een range-query op de eerste vijf tekens van de hash, zodat het wachtwoord zelf uw omgeving niet verlaat.
- Geef altijd dezelfde foutmelding en dezelfde responstijd. Laat inloggen, wachtwoordherstel en registratie nooit verraden of een e-mailadres bekend is.
- Bescherm elke ingang. API’s, mobiele clients, oude protocollen, wachtwoordherstel en de verificatie van eenmalige codes hebben dezelfde limieten nodig als het webformulier.
- Log en alarmeer op patronen, niet op losse pogingen. Meet de verhouding tussen mislukte en geslaagde aanmeldingen per minuut en waarschuw de gebruiker bij een aanmelding vanaf een nieuw apparaat of een nieuwe locatie.
- Voeg een tweede horde toe bij verdacht verkeer. Een CAPTCHA of proof of work na een aantal mislukte pogingen raakt geautomatiseerd verkeer hard en gewone gebruikers nauwelijks.
Bronnen
Veelgestelde vragen
Wat is het verschil tussen brute force en credential stuffing?
Bij brute force raadt de aanvaller: hij probeert wachtwoorden uit een lijst of uit een tekenreeksgenerator tot er één past. Bij credential stuffing raadt hij niet, maar gebruikt hij complete combinaties van gebruikersnaam en wachtwoord die bij een ander bedrijf zijn gelekt. Credential stuffing heeft daardoor veel minder pogingen nodig en slaagt vaker, omdat veel mensen hetzelfde wachtwoord op meerdere plaatsen gebruiken.
Helpt het blokkeren van een account na vijf mislukte pogingen?
Maar gedeeltelijk, en het kan zich tegen u keren. Een blokkade per account stopt het raden op één slachtoffer, maar niet password spraying, waarbij de aanvaller één wachtwoord tegen duizenden accounts probeert en per account onder de limiet blijft. Bovendien kan iemand met een lijst e-mailadressen zo uw hele gebruikersbestand buitensluiten. Vertragen, tijdelijk blokkeren en ook per bron tellen werkt beter dan hard afsluiten.
Stopt MFA credential stuffing volledig?
MFA is verreweg de sterkste maatregel, maar hij is niet absoluut. Een aanvaller die het wachtwoord al heeft, kan proberen de tweede factor te omzeilen via MFA fatigue, via phishing van een eenmalige code of via een endpoint dat de code zelf niet begrenst. Beperk daarom ook het aantal pogingen op de verificatiestap en geef de voorkeur aan phishingbestendige factoren zoals passkeys of een hardwaresleutel.
Hoe controleer ik of een wachtwoord in een datalek voorkomt?
Dat kan zonder het wachtwoord te versturen. U berekent lokaal de SHA-1-hash, stuurt alleen de eerste vijf tekens daarvan naar een dienst met een lijst van gelekte hashes en vergelijkt de teruggegeven staarten zelf. Deze range-methode is de manier waarop Have I Been Pwned zijn wachtwoordlijst aanbiedt. Voer de controle uit bij registratie en bij elke wachtwoordwijziging.
Verwante artikelen
- BegrippenPentestEen pentest is een gecontroleerde aanval op uw systemen door ethische hackers. Lees hoe een penetratietest werkt en welke kwetsbaarheden u ermee vindt.
- KwetsbaarhedenCWE-287A07:2021Broken authenticationBroken authentication uitgelegd: hoe aanvallers via brute force, gelekte wachtwoorden en voorspelbare sessietokens accounts overnemen, en wat u eraan doet.
- KwetsbaarhedenCWE-384A07:2021Session fixationSession fixation uitgelegd: hoe een aanvaller vooraf een session id vastlegt, waarom die na het inloggen geldig blijft en hoe sessierotatie het stopt.