Aller au contenu

Chiffrement au niveau champ dans une base de données

Chiffrement au niveau champ dans une base de données

Section intitulée « Chiffrement au niveau champ dans une base de données »

Le chiffrement au niveau champ protège certaines valeurs avant leur stockage, au lieu de chiffrer indistinctement le disque ou l’ensemble de la base. Il faut le réserver aux données dont la lecture par un administrateur de base, un export SQL ou une sauvegarde volée constituerait déjà un incident.

→ Lire l’explication complète de la marmotte

Champ chiffré : la frontière de sécurité réelle

Section intitulée « Champ chiffré : la frontière de sécurité réelle »

Le chiffrement au repos protège principalement contre le vol d’un disque, d’un fichier de données ou d’une sauvegarde non déchiffrée. Une base démarrée possède déjà les clés nécessaires pour servir ses requêtes. Un compte administrateur ayant accès au moteur, à une réplication logique ou à un export peut donc lire les colonnes protégées par le seul chiffrement au repos.

Le chiffrement au niveau champ change cette frontière : la base ne reçoit que le texte chiffré pour les colonnes concernées. La clé de déchiffrement reste dans le service applicatif, dans un système de gestion de clés, ou dans un HSM (Hardware Security Module), un équipement qui conserve les clés cryptographiques sans les exposer à l’application.

La recommandation est nette : chiffrer côté application les champs à haute sensibilité, pas côté SQL, sauf si le moteur garantit une séparation de clés réellement indépendante de ses administrateurs. Les extensions SQL de chiffrement sont pratiques, puis la clé finit dans un paramètre de session, une procédure stockée ou un fichier de configuration. La commodité adore se déguiser en architecture.

Les cas d’usage légitimes comprennent notamment :

  • identifiants gouvernementaux, numéros de documents et coordonnées bancaires ;
  • secrets de récupération ou réponses à des questions de sécurité ;
  • données sociales dont la consultation doit être limitée à un sous-ensemble de services ;
  • informations personnelles présentes dans une base partagée entre plusieurs domaines applicatifs ;
  • données exportées vers des environnements d’analyse où seules certaines colonnes doivent rester opaques.

Le chiffrement de chaque colonne n’est pas un réflexe de maturité. Chiffrer un statut, une date technique ou une référence nécessaire à toutes les jointures détruit les capacités de requête pour un bénéfice dérisoire. La bonne unité est la donnée dont l’exposition isolée est déjà inacceptable, pas la table entière parce que le tableau de classification avait une case à cocher.

La stratégie complète de protection reste à articuler avec le chiffrement des données au repos et les contrôles d’accès applicatifs. Le chiffrement de champ réduit la portée d’une fuite. Il ne remplace ni une politique d’autorisation, ni une journalisation exploitable, ni une segmentation des comptes de service.

Enveloppe de clés, AES-GCM et données associées

Section intitulée « Enveloppe de clés, AES-GCM et données associées »

Une DEK (Data Encryption Key) chiffre les valeurs métier. Une KEK (Key Encryption Key) protège la DEK, généralement dans un KMS (Key Management Service), un service de gestion centralisée des clés, ou dans un HSM. Ce modèle d’enveloppe évite de chiffrer chaque valeur directement avec une clé racine et permet de faire tourner les clés sans réécrire immédiatement toute l’infrastructure cryptographique.

Pour un champ individuel, AES-GCM (Advanced Encryption Standard, Galois/Counter Mode) est un choix raisonnable lorsque la bibliothèque cryptographique maintenue l’implémente correctement. Il fournit confidentialité et intégrité : une modification du texte chiffré ou de son étiquette d’authentification provoque un échec de déchiffrement.

Chaque chiffrement AES-GCM exige un nonce unique pour une même DEK. Le nonce est une valeur publique transmise avec le texte chiffré. Réutiliser un nonce avec la même clé détruit les garanties du mode GCM et peut révéler des relations entre messages, voire permettre des falsifications. Un générateur aléatoire cryptographiquement sûr de 96 bits convient si le volume par clé reste borné et surveillé. Pour des cadences très élevées, un compteur persistant exige une coordination entre instances, donc une raison supplémentaire de préférer des DEK courtes et segmentées.

Les données associées authentifiées doivent contenir le contexte immuable de la valeur : nom de table, nom de colonne, identifiant stable d’enregistrement et version du format. Ces données ne sont pas chiffrées, mais toute substitution entre deux lignes ou entre deux colonnes échoue au déchiffrement. Sans elles, un attaquant capable de modifier la base peut déplacer un texte chiffré valide d’un compte à un autre. Le chiffrement n’empêche pas la créativité administrative, il force seulement celle-ci à échouer bruyamment.

Une valeur stockée devrait inclure, au minimum, la version du format, l’identifiant de DEK, le nonce, le texte chiffré et l’étiquette d’authentification. Conserver l’identifiant de clé avec chaque valeur permet de déchiffrer les données anciennes après rotation. Ne jamais stocker la DEK dans la même ligne, la même base ou le même secret applicatif que le texte chiffré. Cela revient à mettre le double de la clé sous le paillasson, avec une étiquette.

Le compromis central est brutal : plus un champ est protégé contre l’observation, moins il est interrogeable. Le chiffrement aléatoire produit une sortie différente pour une même entrée. C’est le mode à retenir pour les valeurs libres, les secrets et les informations où l’égalité ne doit pas être visible. Il interdit en revanche les recherches directes, les index B-tree utiles et les contraintes d’unicité sur la valeur chiffrée.

Le chiffrement déterministe produit la même sortie pour une même entrée sous une même clé. Il rend possibles les recherches d’égalité, mais révèle les répétitions et les fréquences. Sur une colonne de pays, de civilité ou de code postal, cette fuite suffit souvent à reconstruire une part conséquente des valeurs. Le déterminisme n’est pas une optimisation neutre, c’est une divulgation structurée.

Pour rechercher une égalité sans exposer le texte chiffré, stocker un index aveugle distinct : un HMAC (Hash-based Message Authentication Code), calculé avec une clé dédiée sur une forme normalisée de la donnée. Une recherche calcule le même HMAC et interroge une colonne indexée. La clé d’index ne doit jamais être la DEK. Sinon, une compromission de la fonction de recherche devient aussi une compromission du chiffrement, ce qui est une façon assez élégante de réduire deux contrôles à un seul problème.

Un index aveugle divulgue toujours l’égalité, la fréquence et la présence d’une valeur candidate si l’espace de recherche est petit. Un numéro de département, un pays ou une date de naissance se devine par énumération. Ajouter un secret dans le calcul empêche le calcul direct par un attaquant sans clé, mais ne masque pas les fréquences déjà visibles dans la base.

Les recherches par préfixe, intervalle, tri et agrégation ne sont pas compatibles avec un chiffrement de champ robuste. Les schémas de chiffrement ordonnable ou de recherche sophistiquée ajoutent des fuites spécifiques et une complexité de sécurité considérable. Les slides promettent des requêtes SQL magiques sur données chiffrées ; les modèles de fuite, eux, ne lisent pas les slides. Pour les rares besoins réels, isoler une vue métier minimale, accepter une recherche applicative limitée ou revoir le besoin fonctionnel.

Le coût de performance vient de quatre endroits : appels au gestionnaire de clés, chiffrement et déchiffrement, gonflement des données encodées, perte d’indexation native. Une DEK mise en cache en mémoire de processus réduit la latence, à condition d’avoir une durée de vie courte, une limite de taille et une invalidation après rotation ou incident. Mettre en cache une clé racine dans Redis est un raccourci vers une réunion pénible avec des gens qui disent « périmètre de confiance ».

Exemple reproductible : valeur AES-GCM et index aveugle

Section intitulée « Exemple reproductible : valeur AES-GCM et index aveugle »

Cet exemple Python chiffre un numéro de document avec AES-GCM et produit un index aveugle pour une recherche exacte. Il nécessite Python 3.10 ou supérieur et le paquet cryptography version 42 ou supérieure. Les clés doivent provenir d’un gestionnaire de secrets en exploitation, pas d’une variable collée dans un manifeste Kubernetes.

# pip install "cryptography>=42"
# Générer une fois des clés de 32 octets, puis les stocker hors de la base.
import base64
import hashlib
import hmac
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
dek = base64.b64decode(os.environ["FIELD_DEK_B64"]) # clé de chiffrement
index_key = base64.b64decode(os.environ["FIELD_INDEX_B64"]) # clé distincte
record_id = "7f7b75d6-60e5-4d29-9407-3c0159b2f4b3"
value = "AB-123-456"
normalized = value.strip().upper()
# Lier cryptographiquement cette valeur à sa ligne et à sa colonne.
aad = f"customers|identity_document|{record_id}|v1".encode()
nonce = os.urandom(12)
ciphertext = AESGCM(dek).encrypt(nonce, normalized.encode(), aad)
blind_index = hmac.new(index_key, normalized.encode(), hashlib.sha256).digest()
# Stocker key_id, nonce, ciphertext et blind_index dans des colonnes séparées.
print(base64.b64encode(nonce).decode())
print(base64.b64encode(ciphertext).decode())
print(base64.b64encode(blind_index).decode())

La colonne d’index aveugle doit être de type binaire et indexée. L’application cherche d’abord les candidats par index, puis déchiffre chaque résultat et compare la valeur normalisée. Cette seconde comparaison n’est pas décorative : elle protège contre les collisions théoriques du HMAC et contre les écarts de normalisation lors d’une migration.

La rotation d’une KEK consiste à déprotéger puis reprotéger les DEK. Elle ne nécessite pas de rechiffrer toutes les valeurs si l’identifiant de DEK est conservé et si le système sait résoudre les anciennes versions. La rotation d’une DEK impose le rechiffrement des champs concernés, généralement par lots idempotents et avec double lecture temporaire pendant la migration.

La révocation d’une clé rend les données indéchiffrables. C’est parfois l’objectif, mais jamais un plan de reprise. Avant toute suppression, sauvegarder les métadonnées de clés, les politiques d’accès, les identifiants de version et les procédures de restauration. Une sauvegarde de base sans accès aux clés correspond à une boîte noire parfaitement conservée. Très esthétique, assez peu opérationnelle.

Superviser les échecs de déchiffrement par cause : étiquette d’authentification invalide, clé introuvable, autorisation refusée, format inconnu, délai d’appel au gestionnaire de clés. Une hausse d’échecs d’intégrité indique une corruption, une mauvaise migration ou une altération active. Continuer avec une valeur vide ou une valeur par défaut masque l’incident et fabrique des décisions métier fausses.

Limiter aussi les journaux : ne jamais écrire le texte en clair, la DEK, les données associées complètes ou les réponses du gestionnaire de clés. Journaliser l’identifiant de clé, le type d’erreur, le service appelant et l’identifiant technique de l’enregistrement suffit à enquêter. Les contrôles d’identité de service et la fédération restent décrits dans la section identités et accès.

Ce mécanisme ne garantit pas la confidentialité face à une application compromise qui possède l’autorisation de déchiffrer. Il ne protège pas non plus contre un utilisateur métier autorisé qui exfiltre les valeurs lues, ni contre l’inférence statistique via les index aveugles. Le reste doit venir de privilèges minimaux, d’une séparation des rôles, de limites d’export, d’alertes sur les lectures anormales et d’une architecture où tous les services n’obtiennent pas toutes les clés.

Sans chiffrement au niveau champ, les valeurs les plus sensibles restent lisibles par tout ce qui touche la base au-delà du disque : un administrateur de base, un export SQL, une sauvegarde volée ou une réplique deviennent autant de copies exploitables en clair. Le chiffrement du disque ne protège que contre le vol physique du support et laisse la donnée déchiffrée dès que la base est montée. Son absence signifie donc qu’une compromission des accès logiques, bien plus fréquente, expose directement les valeurs qui constituaient déjà un incident à la simple lecture. La conséquence est que la sauvegarde, censée protéger, devient un vecteur de fuite, et que le périmètre des personnes réellement capables de lire ces champs s’étend silencieusement à tous les rôles d’exploitation. Le cloisonnement recherché, ne rendre lisibles ces valeurs qu’à qui en a besoin, disparaît.

Pour protéger une donnée précise, l’application la transforme avant de l’enregistrer dans la base. Cette transformation utilise une clé secrète et produit une valeur illisible. La base stocke cette valeur, une petite donnée publique nécessaire au déchiffrement, l’identifiant de la clé utilisée et la version du format.

La clé qui chiffre les données n’est pas conservée dans la base. Elle est elle-même protégée par une autre clé, gardée dans un service spécialisé ou dans un équipement prévu pour empêcher son extraction. Quand l’application doit afficher la donnée, elle demande l’autorisation d’utiliser la clé, récupère ou utilise la clé de données, puis vérifie que la valeur n’a pas été modifiée avant de la déchiffrer.

Une même donnée peut aussi produire une empreinte secrète réservée aux recherches exactes. La base peut alors retrouver les lignes ayant la même empreinte, sans connaître la donnée originale. En revanche, elle peut constater que certaines valeurs se répètent.

Si la clé est perdue, les données deviennent illisibles. Si une personne prend le contrôle de l’application autorisée à déchiffrer, le chiffrement ne suffit plus. Il faut donc limiter les droits, surveiller les erreurs et les accès, sauvegarder les informations sur les clés, puis organiser leur renouvellement sans rendre les anciennes données inaccessibles.

À lire aussi

Pages voisines

: les deux pages se citent l’une l’autre.