Direct naar inhoud

Cryptographic failures

CWE-327OWASP A02:2021Bijgewerkt 31 augustus 20266 min leestijd

Cryptographic failures is de verzamelnaam voor gevoelige gegevens die onvoldoende beschermd zijn, doordat cryptografie ontbreekt, verouderd is of verkeerd wordt toegepast. Denk aan wachtwoorden gehasht met MD5, versleuteling in ECB-modus en zelfbedachte algoritmes. De oplossing bestaat uit standaardbouwstenen, Argon2id voor wachtwoorden en AES-GCM voor opgeslagen gegevens.

Vrijwel elke applicatie beschermt iets met cryptografie: wachtwoorden in de database, een sessietoken in een cookie, persoonsgegevens in een back-up. De algoritmes zijn zelden het zwakke punt, de manier waarop ze worden toegepast bijna altijd wel. Hieronder leest u welke fouten het vaakst voorkomen en waarmee u ze vervangt.

Wat zijn cryptographic failures?

Cryptographic failures is de verzamelnaam voor kwetsbaarheden waarbij gevoelige gegevens onvoldoende beschermd zijn, doordat cryptografie ontbreekt, verouderd is of verkeerd wordt toegepast. OWASP voert de categorie sinds 2021 als A02 in de Top 10, onder de eerdere naam Sensitive Data Exposure.

Een alledaagse vergelijking: een kluis is zo sterk als zijn zwakste schakel. De zwaarste deur beschermt niets zolang de sleutel onder de deurmat ligt. AES, voluit Advanced Encryption Standard, is niet gebroken; AES in de verkeerde modus, met een sleutel uit de broncode, beschermt evengoed niets.

De categorie valt uiteen in een handvol terugkerende fouten:

  • Wachtwoorden gehasht met MD5, SHA-1 of kale SHA-256. Snelle hashfuncties, gebouwd voor doorvoer; precies die snelheid maakt ze ongeschikt voor wachtwoorden.
  • Versleuteling in ECB-modus. ECB staat voor Electronic Codebook: elk blok van zestien bytes gaat los door het algoritme, zodat gelijke blokken gelijke cijfertekst opleveren.
  • Een vaste initialisatievector (IV). Een IV uit de broncode maakt versleuteling deterministisch: dezelfde invoer geeft altijd dezelfde uitvoer.
  • Zelfbedachte cryptografie. Een XOR met een vast woord is geen versleuteling maar codering.
  • Versleuteling zonder authenticatie. Cijfertekst zonder integriteitscontrole kan ongemerkt worden aangepast.

Hoe werkt een aanval op zwakke cryptografie?

Een aanvaller die via SQL injection, een gelekte back-up of een gestolen beheeraccount bij de gebruikerstabel komt, heeft geen wachtwoorden maar hashes. Wat daarna gebeurt, hangt af van de gekozen hashfunctie.

Kwetsbaar:

// Opslaan bij registratie
$hash = md5($password);
$pdo->prepare("INSERT INTO users (email, pw_hash) VALUES (?, ?)")
    ->execute([$email, $hash]);

// Controle bij het inloggen
if (md5($input) === $row["pw_hash"]) {
    login($row);
}

Het werk van de aanvaller is offline: hij laadt de hashes in hashcat en probeert per seconde miljarden kandidaten uit een woordenlijst. Bij MD5 is dat rekenwerk triviaal, en veelgebruikte wachtwoorden staan kant-en-klaar in openbare tabellen. Zonder salt kraakt hij bovendien alle accounts met hetzelfde wachtwoord in één keer, terwijl uw applicatie geen enkele inlogpoging ziet.

Veilig:

// Argon2id: 64 MiB werkgeheugen, 3 iteraties
$options = ["memory_cost" => 65536, "time_cost" => 3, "threads" => 2];
$hash = password_hash($password, PASSWORD_ARGON2ID, $options);

// Inloggen, inclusief migratie van oude hashes
if (password_verify($input, $row["pw_hash"])) {
    if (password_needs_rehash($row["pw_hash"], PASSWORD_ARGON2ID, $options)) {
        store_hash($row["id"], password_hash($input, PASSWORD_ARGON2ID, $options));
    }
    login($row);
}

Argon2id is bewust traag en geheugenintensief, en juist dat geheugen maakt parallelliseren op een videokaart onaantrekkelijk. De salt zit in het resultaat verwerkt, zodat gelijke wachtwoorden verschillende hashes krijgen. Een dump blijft vervelend, maar bulk kraken is er niet meer bij.

Het tweede patroon zit in de opslag van de gegevens zelf.

Kwetsbaar:

const crypto = require("node:crypto");

// Sleutel en IV staan hard in de code en veranderen nooit
const KEY = Buffer.from("0123456789abcdef0123456789abcdef");
const IV = Buffer.alloc(16, 0);

// ECB negeert de IV en versleutelt elk blok los, CBC gebruikt
// steeds dezelfde IV. Geen van beide authenticeert de cijfertekst.
function encrypt(plaintext, mode) {
  const c = crypto.createCipheriv(mode, KEY, mode.endsWith("ecb") ? null : IV);
  return Buffer.concat([c.update(plaintext, "utf8"), c.final()]);
}

Beide varianten zijn deterministisch, en daar zit het lek. In ECB blijven gelijke blokken ook versleuteld gelijk, zodat de structuur van uw gegevens zichtbaar blijft; de klassieke demonstratie is een afbeelding die versleuteld nog altijd herkenbaar is. Bij CBC met een vaste IV lekt de gelijkheid van hele berichten: wie de tabel inziet, ziet welke records dezelfde waarde bevatten. Zonder authenticatietag past een aanvaller de cijfertekst bovendien gericht aan, en een applicatie die anders reageert op verkeerde padding vormt een padding oracle waarmee de hele leestekst valt te herstellen.

Veilig:

const crypto = require("node:crypto");
const key = loadKeyFromKms(); // 32 bytes, niet uit de repository

function encrypt(plaintext) {
  const iv = crypto.randomBytes(12); // uniek per bericht
  const c = crypto.createCipheriv("aes-256-gcm", key, iv);
  const ct = Buffer.concat([c.update(plaintext, "utf8"), c.final()]);
  return Buffer.concat([iv, c.getAuthTag(), ct]);
}

function decrypt(blob) {
  const d = crypto.createDecipheriv("aes-256-gcm", key, blob.subarray(0, 12));
  d.setAuthTag(blob.subarray(12, 28));
  // final() werpt een fout zodra één bit is gewijzigd
  return Buffer.concat([d.update(blob.subarray(28)), d.final()]).toString();
}

AES-GCM, voluit Galois/Counter Mode, versleutelt en authenticeert in één bewerking. De nonce is uniek per bericht, wordt naast de cijfertekst opgeslagen en hoeft niet geheim te zijn. Manipulatie leidt tot een fout in plaats van tot stilzwijgend verkeerde gegevens. Wie liever geen parameters kiest, gebruikt libsodium.

Bij AES-GCM geldt één harde regel: gebruik een nonce nooit tweemaal met dezelfde sleutel. Twee berichten met dezelfde combinatie leveren een aanvaller het verschil tussen de leesteksten en het materiaal om zelf geldige authenticatietags te maken. Genereer de nonce willekeurig per bericht, of kies XChaCha20-Poly1305, waarvan de nonce ruim genoeg is om botsingen uit te sluiten.

Wat is de impact van cryptographic failures?

Technisch komt het neer op gegevens die u versleuteld dacht te hebben. Gekraakte wachtwoorden geven toegang tot uw applicatie en, doordat gebruikers wachtwoorden hergebruiken, tot hun accounts elders. Slecht versleutelde velden leveren persoonsgegevens of betaalgegevens leesbaar op, en wie een versleutelde cookie kan aanpassen, verandert daarmee soms een rol of een bedrag.

Zakelijk begint het bij het datalek. De vraag is dan of de gegevens voor onbevoegden werkelijk onleesbaar waren; verouderde cryptografie telt daarbij niet mee, zodat een incident alsnog gemeld en aan betrokkenen gecommuniceerd moet worden. Herstel is duur, want elk wachtwoord opnieuw laten instellen en elke kolom opnieuw versleutelen raakt de hele keten.

De classificatie loopt daarom van middel tot hoog. Een verouderd algoritme op gegevens die toch al openbaar zijn, is een nette bevinding zonder drama. Dezelfde fout op de wachtwoordtabel is dat niet.

Hoe spoort u cryptographic failures op?

Begin in de code. Zoek op md5, sha1, DES, RC4 en op ECB in de naam van een cipher, en op sleutels of IV’s die als letterlijke waarde in een bestand staan. Kijk ook naar de generator achter tokens en herstellinks: Math.random en rand zijn niet cryptografisch veilig.

In de database is het formaat van de hash meteen zichtbaar: tweeëndertig hexadecimale tekens wijzen op MD5, veertig op SHA-1, terwijl bcrypt met $2y$ begint en Argon2id met $argon2id$. Van buitenaf laat u dezelfde waarde tweemaal versleutelen en vergelijkt u de uitvoer; identieke cijfertekst betekent ECB of een vaste IV. Bij een versleutelde cookie verandert u één byte om te zien of de applicatie dat afwijst of gewoon doorwerkt.

Scanners vinden de transportkant en bekende zwakke ciphers, maar zien niet dat uw opslaglaag ECB gebruikt of dat een sleutel al jaren dezelfde is. Statische analyse komt verder, een code review verder nog. AssistSec neemt de cryptografische keuzes in uw applicatie mee in een penetratietest en beoordeelt daarbij zowel de opslag van wachtwoorden als het sleutelbeheer.

Hoe voorkomt u cryptographic failures?

  • Hash wachtwoorden met Argon2id. Kies bewuste parameters voor geheugen en iteraties, en wijk alleen uit naar bcrypt of scrypt als Argon2id ontbreekt. Kale MD5, SHA-1 of SHA-256 zijn nooit een optie.
  • Migreer bestaande hashes bij het inloggen. Controleer bij elke geslaagde login of het formaat nog voldoet en hash opnieuw; voor slapende accounts dwingt u een reset af.
  • Versleutel uitsluitend geauthenticeerd. Gebruik AES-GCM of XChaCha20-Poly1305, nooit ECB, en genereer per bericht een nieuwe nonce.
  • Schrijf zelf geen cryptografie. Gebruik libsodium of de standaardbibliotheek van uw platform; een eigen constructie faalt niet zichtbaar, maar stil.
  • Beheer sleutels buiten de code. Bewaar ze in een vault, gebruik aparte sleutels per doel en werk rotatie uit voordat u die nodig hebt.
  • Gebruik een veilige generator voor alles wat onvoorspelbaar moet zijn. Sessietokens en API-sleutels komen uit crypto.randomBytes, secrets of SecureRandom.
  • Dwing TLS af en houd de configuratie modern. Sluit oude protocolversies en ciphers uit en zet HSTS aan.

Bronnen

Veelgestelde vragen

Mag ik MD5 of SHA-256 nog gebruiken voor wachtwoorden?

Nee. MD5, SHA-1 en SHA-256 zijn ontworpen om zoveel mogelijk data per seconde te verwerken, en op een moderne videokaart levert dat miljarden pogingen per seconde op. Een wachtwoordhash moet juist traag en geheugenintensief zijn. Gebruik Argon2id, of bcrypt of scrypt als uw platform Argon2id niet aanbiedt.

Wat is er mis met de ECB-modus?

ECB versleutelt elk blok van zestien bytes onafhankelijk van de rest. Gelijke blokken leveren daardoor gelijke cijfertekst op, zodat de structuur van uw gegevens zichtbaar blijft; de klassieke demonstratie is een afbeelding die na versleuteling nog altijd herkenbaar is. Bovendien biedt ECB geen enkele bescherming tegen manipulatie van de cijfertekst.

Argon2id of bcrypt, wat kies ik?

Argon2id heeft de voorkeur, omdat het naast rekentijd ook werkgeheugen eist en daarmee het voordeel van gespecialiseerde hardware wegneemt. Bcrypt blijft een verdedigbare keuze wanneer Argon2id niet beschikbaar is, mits u de kostenfactor periodiek verhoogt. Wat u in beide gevallen niet doet, is zelf een salt-en-hash-constructie in elkaar zetten.

Is HTTPS genoeg om gevoelige gegevens te beschermen?

Nee. TLS beschermt gegevens onderweg tussen browser en server, maar zegt niets over de opslag daarna. Een database met wachtwoorden in MD5 of persoonsgegevens in ECB is even kwetsbaar op een server die uitsluitend HTTPS aanbiedt. Beschouw transport en opslag als twee losse vraagstukken.

Is AES-CBC onveilig?

CBC is niet gebroken, maar het is een modus zonder ingebouwde integriteitscontrole en met scherpe randen: een unieke, onvoorspelbare IV per bericht is verplicht en de cijfertekst moet apart geauthenticeerd worden. In de praktijk gaat dat vaak mis. AES-GCM of XChaCha20-Poly1305 regelt versleuteling en authenticatie in één bewerking en is daarom de betere standaardkeuze.

Verwante artikelen

Druk op / om te zoeken · Esc