« Je l'ai encodé, donc c'est protégé »
La leçon 11 a vu HSTS forcer le HTTPS sur toute la connexion. Mais encore faut-il que ce HTTPS s'appuie sur une vraie crypto, pas sur un base64 pris pour du chiffrement. C'est exactement le piège dans lequel tombe ce dev :
Il veut protéger les clés d'API dans son fichier de config. Il les passe en base64, voit une bouillie illisible, et se dit que c'est sécurisé :
API_KEY=c2stbGl2ZS04YTdkM2UtcHJvZA==
Un attaquant qui lit le fichier tape une commande, une seule :
echo 'c2stbGl2ZS04YTdkM2UtcHJvZA==' | base64 -d
sk-live-8a7d3e-prod
En une seconde, la clé est en clair. Le base64 n'est pas du chiffrement : c'est juste une autre façon d'écrire les mêmes octets. N'importe qui peut le relire, sans aucune clé. Cette confusion entre encoder, hacher et chiffrer est à l'origine d'innombrables fuites. C'est lié à l'OWASP 2025 (A04 Cryptographic Failures).
Encoder, hacher, chiffrer : ne jamais confondre
Trois opérations, trois buts différents. Les mélanger, c'est créer la faille.
- Encoder (base64, URL-encoding) : changer la forme d'une donnée pour la transporter. Réversible par tous, sans clé. Ça ne protège rien. C'est juste un autre alphabet.
- Hacher (SHA-256, bcrypt) : transformer une donnée en empreinte, à sens unique. On ne revient jamais en arrière. Sert à vérifier l'intégrité et à stocker les mots de passe (leçon 7).
- Chiffrer (AES, RSA) : rendre une donnée illisible, réversible avec une clé. Sert à protéger un secret qu'on devra relire. Sans la clé, illisible.
La règle tient en une ligne : encoder pour transporter, hacher pour vérifier ou stocker un mot de passe, chiffrer pour protéger un secret qu'on relira. Le base64 du début n'était ni un hachage ni un chiffrement : juste un déguisement, retiré en une commande.
Le faux remède : « je l'ai encodé en base64 » ou « j'ai écrit mon petit algo maison » ne protège rien. L'encodage se décode, et un algo bricolé se casse en minutes. La sécurité ne vient pas du secret de la méthode, mais d'une vraie crypto avec une vraie clé (section 4).
À vous d'attaquer : cassez la fausse protection
Vous avez volé un secret « protégé ». Choisissez la méthode de protection, puis essayez de le casser sans la clé. Vous verrez tomber le base64 et la crypto maison en un clic, et l'AES-256 résister. Tout est calculé dans votre navigateur.
Ce qui vient de se passer
base64 se décode avec une fonction standard (atob, base64 -d) : aucune clé, aucune protection. La crypto maison (XOR à clé courte) se casse presque aussi vite : la clé se devine ou se force, et le motif se voit. Les deux n'étaient que de l'obscurité.
AES-256, lui, résiste : sans la clé, il faudrait essayer 2256 possibilités, plus que d'atomes sur Terre. C'est ça, du vrai chiffrement : la sécurité tient à la clé, pas au secret de l'algorithme (qui, lui, est public et étudié par le monde entier).
Le correctif : la vraie crypto, et la règle d'or
D'abord deux familles de chiffrement. Le symétrique (AES) utilise une seule clé partagée, rapide. L'asymétrique (RSA, courbes elliptiques) utilise une paire : une clé publique pour chiffrer, une clé privée pour déchiffrer. Cela résout le partage de la clé. En pratique, HTTPS combine les deux : l'asymétrique sert à échanger une clé symétrique, puis le symétrique fait le gros du travail, plus vite.
Côté code, on n'écrit pas la crypto soi-même : on appelle une bibliothèque éprouvée. En PHP, libsodium est intégré et fait du chiffrement authentifié (chiffré + protégé contre la modification) :
$cle = sodium_crypto_secretbox_keygen(); // clé aléatoire (gardée à part)
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // nonce unique à chaque fois
$chiffre = sodium_crypto_secretbox($message, $nonce, $cle); // chiffré + authentifié
$clair = sodium_crypto_secretbox_open($chiffre, $nonce, $cle); // déchiffré
Deux autres réflexes essentiels. HTTPS/TLS chiffre tout ce qui transite (cookies, mots de passe) : sans lui, tout passe en clair sur le réseau (leçon 8). Le certificat est gratuit (Let's Encrypt), et on ajoute HSTS (leçon 11). Et les secrets (clés, mots de passe de base) ne vivent jamais en dur dans le code : ils finiraient dans l'historique git. Mettez-les ailleurs : des variables d'environnement, un fichier .env non versionné et hors du dossier web, ou un gestionnaire de secrets.
La règle d'or : n'inventez jamais votre propre algorithme de chiffrement. Un bon algorithme est public et résiste quand même (principe de Kerckhoffs) : sa solidité vient de la clé, pas du secret du code. Les algos standards ont déjà encaissé des années d'attaques ; le vôtre repartirait de zéro, sans cette épreuve du feu. Utilisez AES-GCM ou libsodium, jamais le mode ECB (qui laisse voir les motifs), et ne réutilisez jamais un nonce.
Défense en profondeur :
- le bon outil : encoder pour transporter, hacher pour les mots de passe (bcrypt/Argon2, leçon 7), chiffrer pour un secret relisible ;
- une bibliothèque éprouvée (libsodium), du chiffrement authentifié, jamais ECB, nonce unique ;
- HTTPS partout (+ HSTS), certificat Let's Encrypt ;
- les secrets hors du code :
.envnon versionné, gestionnaire de secrets, rotation.
Référence : OWASP Cryptographic Storage Cheat Sheet.
La méthode et l'arsenal du pentester
On vient de voir comment se défendre. Voilà maintenant comment un attaquant lit exactement ce que vous croyez avoir caché.
1. Repérer la fausse protection. Une chaîne qui finit par == sent le base64 ; eyJ... est un JWT (JSON Web Token, un jeton d'authentification encodé en base64, donc lisible sans aucune clé). Un cookie « chiffré » qui se décode tout seul, un token « secret » qui n'est que de l'encodage : on le voit vite.
2. Identifier l'algorithme. La longueur trahit le hash : 32 caractères hexa = md5, 40 = sha1, 64 = sha256. Le format (hexa, base64) et le mode donnent le reste.
3. Casser le faible. Hash non salé → rainbow tables (leçon 7). Clé courte ou maison → force brute, analyse de fréquence. Nonce réutilisé → la confidentialité tombe. C'est presque toujours la mauvaise utilisation qu'on casse, pas l'algorithme lui-même.
L'arsenal.
- CyberChef : le couteau suisse. Décode base64/hexa/URL, casse ROT/XOR, identifie un hash, le tout en quelques clics. À avoir sous la main.
- hashcat / John the Ripper : casser les hash (leçon 7).
- testssl.sh / SSL Labs : auditer la config TLS d'un serveur (vieux protocoles, ciphers faibles, certificat).
Les pièges qui font fuiter
On ne reviendra pas sur la confusion encoder/chiffrer (vue plus haut). Trois autres erreurs reviennent sans cesse :
1. Chiffrer les mots de passe au lieu de les hacher. Le chiffrement est réversible : si la clé fuite, tous les mots de passe fuitent d'un coup. On les hache (bcrypt/Argon2, leçon 7), un sens unique d'où l'on ne revient pas.
2. Inventer son algorithme. « Personne ne connaît mon chiffrement » est l'erreur historique : la sécurité par l'obscurité ne tient pas. La solidité vient de la clé, pas du secret du code.
3. Laisser un secret dans le code. Une clé en dur reste dans l'historique git ; une fois commitée, la retirer ne suffit pas, il faut la changer (rotation).
Trois pièges, un seul remède : la checklist ci-dessous.
La checklist crypto
À se poser dès qu'on touche à une donnée sensible.
- Le bon outil : encoder pour transporter, hacher pour vérifier/stocker un mot de passe, chiffrer pour un secret relisible.
- Mots de passe : bcrypt ou Argon2 (leçon 7), jamais chiffrés, jamais en md5/sha1.
- Chiffrement : libsodium ou AES-GCM (authentifié), jamais ECB, nonce unique à chaque fois.
- Transport : HTTPS/TLS partout, certificat Let's Encrypt, HSTS.
- Secrets : hors du code (
.envnon versionné, gestionnaire de secrets), rotation, jamais commités. - Règle d'or : jamais son propre algorithme de chiffrement.
Les références. La OWASP Cryptographic Storage Cheat Sheet donne les bons choix par cas d'usage. Pour coder : la doc de libsodium (et son binding PHP intégré). Pour jouer avec encodages et hash : CyberChef.
Rappel. Casser la « crypto » d'un système qui n'est pas le vôtre reste une attaque. On ne teste que ses propres systèmes ou une cible explicitement autorisée (leçon 1).
"I encoded it, so it's protected"
Lesson 11 showed HSTS forcing HTTPS across the whole connection. But that HTTPS is only as good as the crypto underneath it — not a base64 mistaken for encryption. That's exactly the trap this dev falls into:
They want to protect the API keys in their config file. They run them through base64, see an unreadable blob, and figure it's secure:
API_KEY=c2stbGl2ZS04YTdkM2UtcHJvZA==
An attacker who reads the file types one command, just one:
echo 'c2stbGl2ZS04YTdkM2UtcHJvZA==' | base64 -d
sk-live-8a7d3e-prod
In one second, the key is in clear. base64 is not encryption: it's just another way to write the same bytes. Anyone can read it back, with no key. This confusion between encoding, hashing and encrypting is behind countless leaks. It maps to OWASP 2025 (A04 Cryptographic Failures).
Encode, hash, encrypt: never confuse them
Three operations, three different goals. Mixing them up creates the flaw.
- Encode (base64, URL-encoding): change a data's shape to transport it. Reversible by anyone, no key. It protects nothing. It's just a different alphabet.
- Hash (SHA-256, bcrypt): turn data into a fingerprint, one-way. You never go back. Used to verify integrity and to store passwords (lesson 7).
- Encrypt (AES, RSA): make data unreadable, reversible with a key. Used to protect a secret you'll need to read back. Without the key, unreadable.
The rule fits in one line: encode to transport, hash to verify or store a password, encrypt to protect a secret you'll read back. The dev's base64 from the start was neither hashing nor encryption: just a disguise, removed with one command.
Beware the false cure: "I base64-encoded it" or "I wrote my own little algorithm" protects nothing. Encoding gets decoded, and a homemade algorithm breaks in minutes. Security doesn't come from the secrecy of the method, but from real crypto with a real key (section 4).
Your turn to attack: break the fake protection
You've stolen a "protected" secret. Pick the protection method, then try to break it without the key. You'll watch base64 and homemade crypto fall in one click, and AES-256 hold. Everything is computed in your browser.
What just happened
base64 decodes with a standard function (atob, base64 -d): no key, no protection. Homemade crypto (short-key XOR) breaks almost as fast: the key is guessed or brute-forced, and the pattern shows. Both were just obscurity.
AES-256 holds: without the key, you'd have to try 2256 possibilities, more than there are atoms on Earth. That's real encryption: security rests on the key, not on the secrecy of the algorithm (which is public and studied by the whole world).
The fix: real crypto, and the golden rule
First, two families of encryption. Symmetric (AES) uses one shared key, fast. Asymmetric (RSA, elliptic curves) uses a pair: a public key to encrypt, a private key to decrypt. It solves key sharing. In practice, HTTPS combines both: asymmetric exchanges a symmetric key, then symmetric does the heavy lifting, faster.
On the code side, you don't write the crypto yourself: you call a vetted library. In PHP, libsodium is built in and does authenticated encryption (encrypted + protected against tampering):
$key = sodium_crypto_secretbox_keygen(); // random key (kept separately)
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // a unique nonce each time
$cipher = sodium_crypto_secretbox($message, $nonce, $key); // encrypted + authenticated
$plain = sodium_crypto_secretbox_open($cipher, $nonce, $key); // decrypted
Two more essential reflexes. HTTPS/TLS encrypts everything in transit (cookies, passwords): without it, everything travels in clear on the network (lesson 8). The certificate is free (Let's Encrypt), and you add HSTS (lesson 11). And secrets (keys, database passwords) never live hardcoded in the code: they'd end up in the git history. Put them elsewhere: environment variables, an unversioned .env file outside the web root, or a secret manager.
The golden rule: never roll your own crypto. A good algorithm is public and holds anyway (Kerckhoffs's principle): its strength comes from the key, not the secrecy of the code. The standard algorithms have already survived years of attacks. Inventing your own starts from scratch, without that trial by fire. Use AES-GCM or libsodium, never ECB mode (which leaks patterns), and never reuse a nonce.
Defense in depth:
- the right tool: encode to transport, hash for passwords (bcrypt/Argon2, lesson 7), encrypt for a readable-back secret;
- a vetted library (libsodium), authenticated encryption, never ECB, a unique nonce;
- HTTPS everywhere (+ HSTS), a Let's Encrypt certificate;
- secrets out of the code: unversioned
.env, a secret manager, rotation.
Reference: OWASP Cryptographic Storage Cheat Sheet.
The pentester's method and arsenal
You now know how to defend. Here's exactly how an attacker reads what you thought you'd hidden.
1. Spot the fake protection. A string ending in == smells of base64; eyJ... is a JWT (JSON Web Token, an authentication token base64-encoded — so readable with no key). A "encrypted" cookie that decodes on its own, a "secret" token that's only encoding: you see it fast.
2. Identify the algorithm. Length gives away the hash: 32 hex characters = md5, 40 = sha1, 64 = sha256. The format (hex, base64) and mode give the rest.
3. Break the weak one. Unsalted hash → rainbow tables (lesson 7). Short or homemade key → brute force, frequency analysis. Reused nonce → confidentiality collapses. It's almost always the misuse you break, not the algorithm itself.
The arsenal.
- CyberChef: the Swiss army knife. Decodes base64/hex/URL, breaks ROT/XOR, identifies a hash, all in a few clicks. Keep it handy.
- hashcat / John the Ripper: crack hashes (lesson 7).
- testssl.sh / SSL Labs: audit a server's TLS config (old protocols, weak ciphers, certificate).
The traps that cause leaks
We won't revisit the encode/encrypt confusion (covered above). Three other mistakes come up again and again:
1. Encrypting passwords instead of hashing them. Encryption is reversible: if the key leaks, all passwords leak at once. You hash them (bcrypt/Argon2, lesson 7), a one-way street you can't come back from.
2. Inventing your own algorithm. "No one knows my cipher" is the historic mistake: security through obscurity doesn't hold. Strength comes from the key, not the secrecy of the code.
3. Leaving a secret in the code. A hardcoded key stays in the git history; once committed, removing it isn't enough, you must change it (rotation).
Three traps, one remedy: the checklist below.
The crypto checklist
To ask yourself as soon as you touch sensitive data.
- The right tool: encode to transport, hash to verify/store a password, encrypt for a readable-back secret.
- Passwords: bcrypt or Argon2 (lesson 7), never encrypted, never md5/sha1.
- Encryption: libsodium or AES-GCM (authenticated), never ECB, a unique nonce each time.
- Transport: HTTPS/TLS everywhere, a Let's Encrypt certificate, HSTS.
- Secrets: out of the code (unversioned
.env, secret manager), rotation, never committed. - Golden rule: never your own crypto.
The references. The OWASP Cryptographic Storage Cheat Sheet gives the right choices per use case. For coding: the libsodium docs (and its built-in PHP binding). To play with encodings and hashes: CyberChef.
Reminder. Breaking the "crypto" of a system that isn't yours is still an attack. Only test your own systems or an explicitly authorized target (lesson 1).
Un dev « sécurise » ses clés d'API en les passant en base64 dans le fichier de config. Un attaquant vole le fichier. Avant de dérouler : en combien de temps récupère-t-il les clés ? Et si elles étaient chiffrées en AES-256 avec la clé gardée ailleurs ?
Voir la réponse
En une seconde avec base64 : c'est un encodage, pas un chiffrement. base64 -d (ou n'importe quel outil en ligne) rend les clés en clair, sans aucune clé secrète. Avec AES-256 et la clé gardée ailleurs (hors du fichier volé), l'attaquant n'a que du charabia : sans la clé, il faudrait essayer 2256 possibilités, ce qui est hors d'atteinte. Le base64 ne protège rien ; le vrai chiffrement protège tant que la clé reste secrète.
A dev "secures" their API keys by base64-encoding them in the config file. An attacker steals the file. Before you expand: how long to recover the keys? And if they were AES-256 encrypted with the key kept elsewhere?
Show the answer
In one second with base64: it's encoding, not encryption. base64 -d (or any online tool) returns the keys in clear, with no secret key. With AES-256 and the key kept elsewhere (outside the stolen file), the attacker only has gibberish: without the key, they'd have to try 2256 possibilities, which is out of reach. base64 protects nothing; real encryption protects as long as the key stays secret.
🎯 Pratique
S'entraîner (clique pour ouvrir) :
💬 Ré-explique sans regarder
Avec tes mots : quelle est la différence entre encoder, hacher et chiffrer (et à quoi sert chacun), et pourquoi ne faut-il jamais écrire sa propre crypto ?
🧠 Rappel libre
Sans remonter : définis en une phrase chacune encoder, hacher, chiffrer (avec un usage), et donne la règle d'or de la crypto.
⚖️ Juge le code de l'IA
Tu dois protéger des données sensibles en base (des numéros de téléphone). L'IA propose : « Je les encode en base64 avant de les stocker. Comme ça ils ne sont pas en clair dans la base, c'est protégé. » Tu acceptes, ou tu rejettes ?
sodium_crypto_secretbox), du chiffrement authentifié, et surtout la clé gardée hors de la base (sinon voler la base = voler la clé). Idéalement, on se demande aussi si on a vraiment besoin de stocker cette donnée. Le base64, lui, ne fait que déguiser.You protect your secrets and your data. But your code rests on hundreds of dependencies you didn't write. Lesson 13 attacks from there: a flaw in a dependency is your flaw, and how to audit it.
Lesson 13: Dependencies & supply chain →