Chiffrer dans le navigateur avec WebCrypto : le zero-knowledge en pratique
Comment chiffrer côté client, avant tout envoi, pour que le serveur ne voie jamais le clair. Avec du code.
Le zero-knowledge repose sur une idée : chiffrer avant que les données ne quittent l’appareil. Le navigateur en est capable nativement, via l’API WebCrypto. Voyons concrètement comment.
WebCrypto, la crypto native du navigateur
Disponible sous crypto.subtle, elle fournit des primitives sûres (AES-GCM, dérivation de clé, hachage) implémentées par le navigateur — pas de bibliothèque tierce douteuse à charger.
Dériver la clé du mot de passe
const sel = crypto.getRandomValues(new Uint8Array(16));
const baseKey = await crypto.subtle.importKey(
"raw", new TextEncoder().encode(motDePasse), "PBKDF2", false, ["deriveKey"]
);
const cle = await crypto.subtle.deriveKey(
{ name: "PBKDF2", salt: sel, iterations: 200000, hash: "SHA-256" },
baseKey, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]
);
Chiffrer avant l’envoi
const nonce = crypto.getRandomValues(new Uint8Array(12));
const chiffré = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv: nonce }, cle, new TextEncoder().encode(document)
);
// On envoie au serveur : sel + nonce + chiffré — jamais le mot de passe ni le clair.
Ce que le serveur reçoit
Uniquement des données chiffrées, un sel et un nonce. Sans le mot de passe (qui ne quitte jamais l’appareil), il ne peut rien déchiffrer. C’est la définition opérationnelle du zero-knowledge.
Les points de vigilance
- La clé reste en mémoire du navigateur : on la marque non-extractible (
false) et on ne la stocke jamais. - Le sel et le nonce se conservent (non secrets) pour pouvoir déchiffrer.
- La sécurité dépend toujours de la qualité du mot de passe et de l’intégrité de la page servie (HTTPS strict).
Avec quelques dizaines de lignes, le navigateur devient un coffre : le serveur n’est plus qu’un entrepôt de données qu’il ne peut pas lire.
Envie d’aller plus loin avec SecretVault ?
Découvrir SecretVault