Aller au contenu

Comment sécuriser Redis et Memcached distribués

Un cache distribué réduit la latence et soulage les bases de données, mais il place aussi des données et des décisions applicatives sur un chemin très fréquenté. Redis et Memcached ne doivent jamais être traités comme des bibliothèques locales un peu rapides : ce sont des services réseau qui acceptent des commandes, conservent des secrets potentiels et peuvent influencer le comportement métier.

→ Lire l’explication complète de la marmotte

Redis et Memcached : le compromis sécurité-performance

Section intitulée « Redis et Memcached : le compromis sécurité-performance »

Le compromis central est brutal : un cache partagé gagne en latence et en débit, mais paie cette performance par une nouvelle frontière de confiance. Plus le cache est accessible depuis de nombreux services, plus une compromission applicative peut lire, modifier ou supprimer des données appartenant à d’autres services.

La recommandation est nette : réserver Redis aux cas nécessitant structures de données, persistance contrôlée, réplication ou contrôle d’accès par identité applicative ; réserver Memcached à des valeurs jetables, non sensibles et strictement isolées au réseau. Memcached n’offre pas de chiffrement natif des flux ni de mécanisme d’authentification intégré comparable aux listes de contrôle d’accès de Redis. Le placer derrière un pare-feu ne le transforme pas en coffre-fort. Un château gonflable derrière une haie reste un château gonflable.

Redis fournit des listes de contrôle d’accès, ou ACL (Access Control List), depuis Redis 6. Chaque application doit recevoir un compte distinct, limité à ses préfixes de clés et aux commandes nécessaires. Un compte partagé avec accès +@all annule ce bénéfice : la séparation n’existe alors que dans un diagramme d’architecture, cet animal mythologique.

Une clé de cache doit exprimer son domaine de sécurité. Préfixer par tenant:{id}:, service:, environnement et version de schéma évite les collisions accidentelles, mais ne constitue pas une autorisation. La vérification d’accès reste dans l’application ou dans Redis via les ACL. Une convention de nommage n’arrête aucun client authentifié avec des privilèges excessifs.

Les données de session, jetons d’accès, codes de réinitialisation et réponses contenant des données personnelles exigent une décision explicite. Un cache peut les contenir seulement si la durée de vie est courte, si la révocation est gérée hors cache et si le risque de lecture par un service voisin est accepté et documenté. Pour les jetons de session, préférer un identifiant opaque en cache à un jeton signé complet. Une fuite d’identifiants opaques reste grave, mais elle ne livre pas d’emblée les revendications et les signatures transportées par un jeton.

La disponibilité n’est pas une propriété automatique du cluster. Réplication, bascule et sharding répartissent les défaillances, mais une invalidation manquée ou une partition réseau peut livrer une valeur ancienne. La page architecture cyber et les choix entre monolithe et microservices aident à placer ce service dans une frontière applicative cohérente : un cache transverse sans propriétaire devient rapidement une base de données clandestine.

Un cache ne doit écouter que sur une interface privée dédiée ou une interface de boucle locale quand le client est colocalisé. Interdire toute adresse publique, tout routage entrant depuis Internet et toute translation de port opportuniste. Redis a déjà servi de relai d’attaque par amplification via des instances exposées, et Memcached a été massivement exploité de cette manière avec son protocole UDP (User Datagram Protocol). Désactiver UDP sur Memcached sauf besoin démontré, puis filtrer le port au niveau réseau. Le besoin démontré est rarement plus qu’une phrase oubliée dans une slide.

Le chiffrement en transit doit être assuré par Transport Layer Security, ou TLS. Redis prend en charge TLS nativement ; activer la validation du certificat côté client et exiger l’authentification mutuelle, ou mTLS (mutual Transport Layer Security), pour les chemins interservices à forte sensibilité. Le chiffrement sans vérification de certificat protège contre l’écoute passive, pas contre un intermédiaire actif. C’est du cadenas peint sur la porte.

Memcached nécessite généralement un tunnel TLS fourni par le système d’exploitation, un proxy local ou un maillage de services. Cette couche ajoute une dépendance d’exploitation : certificats, renouvellement, identités et supervision du proxy. Si cette dette n’est pas acceptable, Memcached n’est pas le bon choix pour des données sensibles. Ne pas compenser par un mot de passe ajouté dans l’application : le protocole Memcached ne saura ni l’imposer ni l’auditer.

Le plan réseau doit distinguer quatre flux : clients vers cache, nœuds de cache entre eux, sauvegarde éventuelle, administration. Les ports d’administration et les commandes dangereuses doivent être inaccessibles aux identités applicatives. Dans Redis, interdire notamment CONFIG, MODULE, DEBUG, FLUSHALL, FLUSHDB, KEYS, MONITOR, SAVE et BGSAVE aux comptes applicatifs. Certaines commandes exposent des secrets, bloquent l’instance ou permettent de modifier durablement son comportement.

L’administration passe par un bastion, une identité nominative, des journaux centralisés et une séparation des secrets. Le compte de supervision doit pouvoir lire les métriques nécessaires, pas les valeurs métier. Une sonde qui exécute KEYS * toutes les trente secondes n’est pas de l’observabilité, c’est une attaque par déni de service avec un badge officiel. Pour le socle hôte, appliquer les principes de la page Linux : processus non privilégié, système de fichiers restreint, journalisation et mises à jour suivies.

L’empoisonnement de cache consiste à faire stocker ou servir une valeur qui sera consommée comme légitime par une autre requête. L’attaquant n’a pas besoin d’écrire directement dans Redis : il suffit parfois de contrôler un paramètre inclus dans une clé, un en-tête HTTP (Hypertext Transfer Protocol) interprété de manière ambiguë, ou une réponse mise en cache avant contrôle d’autorisation.

La règle est de construire la clé à partir de données normalisées et autorisées. Inclure l’identité du locataire, la version de représentation, la langue si elle modifie la réponse, et les droits lorsqu’ils influencent le contenu. Exclure les en-têtes non maîtrisés, les paramètres décoratifs et toute donnée dont la canonisation varie entre proxy et application. Une réponse authentifiée ne doit jamais être stockée sous une clé accessible à un utilisateur anonyme, même avec une durée de vie de trois secondes. Trois secondes suffisent très bien à un script.

Ne jamais placer dans le cache la décision d’autorisation comme vérité durable sans mécanisme d’invalidation sur changement de droit. La révocation d’un rôle, d’un compte ou d’une session doit provoquer soit une invalidation ciblée, soit une vérification en source d’autorité à intervalle borné. Le cache ne garantit pas que la politique courante est appliquée ; il garantit seulement qu’une valeur précédemment calculée peut être retrouvée.

L’intégrité d’une valeur peut être renforcée par une signature ou un code d’authentification de message, ou MAC (Message Authentication Code), calculé par le producteur et vérifié par le consommateur. Cette mesure est pertinente lorsque plusieurs services partagent l’infrastructure du cache mais ne doivent pas se faire confiance pour les valeurs produites. Elle ne remplace pas les ACL : un service autorisé à supprimer une clé peut toujours provoquer un repli coûteux, et un service qui possède la clé de MAC peut signer n’importe quoi.

Les attaques de type cache stampede, où de nombreuses requêtes recalculent la même valeur après expiration, deviennent aussi un sujet de sécurité quand elles épuisent la base source. Employer expiration avec gigue aléatoire, verrou par clé à durée courte et repli borné. Le verrou doit expirer même si le producteur disparaît. Un verrou éternel est une œuvre contemporaine sur le thème de la panne.

Le prérequis minimal est Redis 6 ou supérieur pour les ACL, une version maintenue par l’éditeur ou la distribution, des clients compatibles TLS et un réseau privé filtré. Prévoir dès le départ la gestion des certificats et mots de passe dans un gestionnaire de secrets, jamais dans une image de conteneur ou un dépôt Git. La page Git et CI/CD couvre les contrôles attendus pour empêcher cette forme très classique de fossilisation du secret.

L’exemple suivant crée un compte applicatif Redis restreint à un préfixe, interdit les catégories de commandes risquées et impose TLS. Les chemins de certificats doivent appartenir à l’utilisateur du service, avec lecture limitée.

# redis.conf : service accessible uniquement sur le réseau privé
bind 10.42.8.15
protected-mode yes
port 0
# TLS obligatoire, certificat serveur et autorité de certification interne
tls-port 6379
tls-cert-file /etc/redis/tls/server.crt
tls-key-file /etc/redis/tls/server.key
tls-ca-cert-file /etc/redis/tls/ca.crt
tls-auth-clients yes
# Le compte applicatif ne manipule que ses clés et les commandes prévues
user api-service on >SECRET_GENERE_PAR_LE_GESTIONNAIRE \
~prod:api-service:* +get +set +del +expire +ttl +pttl \
-@admin -@dangerous -keys -monitor -flushall -flushdb

Tester l’interdiction depuis le même chemin réseau que l’application. Un test exécuté sur la machine d’administration valide surtout que la machine d’administration fonctionne, exploit que l’industrie maîtrise depuis longtemps.

Fenêtre de terminal
# Authentification TLS avec certificat client, puis test d'accès autorisé
redis-cli --tls --cacert /etc/redis/tls/ca.crt \
--cert /etc/redis/tls/client.crt --key /etc/redis/tls/client.key \
--user api-service --pass "$REDIS_PASSWORD" \
SET prod:api-service:probe "ok" EX 60
# Cette commande doit échouer avec NOPERM
redis-cli --tls --cacert /etc/redis/tls/ca.crt \
--user api-service --pass "$REDIS_PASSWORD" FLUSHALL

Faire tourner les mots de passe Redis par recouvrement : créer un nouveau secret, distribuer les clients capables de l’utiliser, vérifier les connexions, puis retirer l’ancien. Les ACL Redis permettent plusieurs mots de passe actifs pour un compte, ce qui évite une coupure globale. Les certificats suivent le même principe : déployer les autorités de certification de confiance avant les nouveaux certificats, puis retirer l’ancienne autorité après migration.

La supervision doit mesurer latence, connexions, refus d’authentification, évictions, mémoire, taux de succès, erreurs de réplication et commandes lentes. Une hausse d’évictions signale soit un dimensionnement insuffisant, soit des durées de vie incompatibles avec le jeu de données. Une hausse de cache miss peut annoncer une attaque, une invalidation massive ou une régression de clé. Corréler ces signaux avec les journaux applicatifs et l’observabilité, plutôt que d’admirer un taux de succès global qui masque une fuite de données.

La sauvegarde Redis doit être traitée comme une sauvegarde de données sensibles. Les fichiers RDB (Redis Database) et AOF (Append Only File) contiennent potentiellement sessions, identifiants et données métier. Chiffrer au repos, limiter les lecteurs, tester la restauration et définir la durée de conservation. Memcached n’est pas une source de vérité et ne doit pas recevoir de stratégie de sauvegarde : après perte, le système doit reconstruire les valeurs depuis une source autoritaire.

Un plan de reprise doit préciser le comportement lors d’un cache indisponible : dégradation fonctionnelle, limites de débit vers la base, délais d’attente courts et circuit de coupure. Rejouer aveuglément toutes les requêtes vers la base après une panne de cache remplace une indisponibilité par deux. Le cache ne garantit ni confidentialité sans chiffrement et contrôle d’accès, ni intégrité sans séparation des producteurs, ni fraîcheur après invalidation ratée, ni disponibilité de la source de données. Ces propriétés doivent venir de l’architecture entière, pas d’un daemon très rapide.

Sans compte distinct par application, chiffrement en transit et filtrage réseau, le cache cesse d’être un accélérateur pour devenir une base de données clandestine ouverte. Un compte partagé en +@all laisse une application compromise lire, modifier ou supprimer les clés des autres services, et exécuter des commandes comme CONFIG, FLUSHALL ou KEYS qui exposent des secrets ou bloquent l’instance. Sans TLS vérifié, un intermédiaire actif lit ou altère les valeurs en transit ; le chiffrement sans contrôle de certificat ne protège que contre l’écoute passive. Une instance exposée sur une adresse publique a déjà servi de relai d’amplification, massivement pour Memcached via UDP. Les sessions, jetons et données personnelles mis en cache deviennent lisibles par un service voisin, et une invalidation manquée sert une valeur périmée à la place de la bonne.

Un cache distribué garde temporairement des informations déjà calculées afin que plusieurs programmes puissent les retrouver sans interroger à chaque fois la base de données. Redis et Memcached sont deux logiciels qui stockent ces informations en mémoire. Comme ils reçoivent des demandes par le réseau, une personne ou un programme non autorisé peut tenter de lire, modifier ou effacer leur contenu s’ils sont exposés.

La première protection consiste à les rendre accessibles seulement depuis les programmes prévus. Redis peut demander un mot de passe et limiter les actions autorisées pour chaque programme. Les échanges doivent être chiffrés afin qu’une personne placée sur le réseau ne puisse pas lire les données pendant leur transport. Memcached ne fournit pas ces protections par lui-même ; il faut donc le placer dans un réseau très fermé ou choisir un autre outil pour des données secrètes.

Une mauvaise information peut être placée dans le cache si le programme construit mal les noms utilisés pour ranger les données. Une réponse destinée à une personne ne doit jamais être retrouvée par une autre. Les droits d’accès changent aussi : lorsqu’un compte perd un droit, les anciennes réponses gardées en mémoire doivent être supprimées ou revérifiées.

Enfin, le cache peut tomber en panne ou perdre son contenu. L’application doit alors ralentir, limiter les demandes vers la base de données et reconstruire les données progressivement. Les secrets, certificats, sauvegardes et journaux doivent être surveillés et renouvelés, sinon la protection disparaît discrètement.

À lire aussi

Pages voisines