La brèche Snowflake 2024 : quand le multi-tenant devient un vecteur d'attaque
En 2024, une vague d'attaques a ciblé les clients de Snowflake, la plateforme cloud de data warehousing. Résultat : 165 entreprises compromises, dont Ticketmaster (560 millions de dossiers clients), Santander et LendingTree. Le vecteur d'attaque n'était pas une vulnérabilité Snowflake elle-même, mais des credentials volés via des malwares sur les postes des employés — sans authentification multi-facteurs pour stopper l'accès.
Cette attaque massive soulève une question fondamentale pour tous les éditeurs de SaaS : dans une architecture multi-tenant, si un attaquant obtient les credentials d'un client, peut-il accéder aux données des autres ? La réponse dépend entièrement de la qualité de l'isolation mise en place. Et dans trop de SaaS "rapidement développés", cette isolation est inexistante ou symbolique.
Chez ADRD Consulting, RecruteX est notre SaaS RH multi-tenant qui héberge les données RH sensibles de 50+ entreprises clientes. Voici comment nous garantissons que la compromission d'un compte n'affecte jamais les autres.
Les 3 modèles d'isolation multi-tenant
Modèle 1 : Base de données séparée par tenant (isolation maximale)
Chaque client a sa propre base de données MySQL. L'isolation est totale : une requête SQL mal formulée ne peut physiquement pas accéder aux données d'un autre client.
Avantages : isolation absolue, sauvegardes et migrations indépendantes, conformité RGPD facilitée.
Inconvénients : coût opérationnel élevé (N bases de données à maintenir), migrations de schéma complexes, impossible à l'échelle avec des centaines de clients sur hébergement mutualisé.
Modèle 2 : Schéma séparé par tenant
Une seule base de données, mais chaque client a son propre schéma (préfixe de tables ou schéma MySQL distinct). Moins coûteux que le modèle 1 mais offre une isolation partielle.
Modèle 3 : Table partagée avec colonne tenant_id (notre choix pour RecruteX)
Toutes les tables partagent la même structure, avec une colonne entreprise_id (ou tenant_id) sur chaque ligne. C'est le modèle le plus économique et le plus scalable — mais il requiert une discipline absolue dans le code pour garantir l'isolation.
L'isolation par entreprise_id dans RecruteX : le détail qui change tout
Chaque requête SQL dans RecruteX inclut obligatoirement la clause WHERE entreprise_id = ? avec l'ID de l'entreprise de l'utilisateur connecté :
// Pattern obligatoire dans RecruteX
$stmt = $pdo->prepare(
"SELECT * FROM candidats
WHERE entreprise_id = :eid
AND statut = :statut
ORDER BY date_creation DESC"
);
$stmt->execute([
':eid' => $_SESSION['entreprise_id'], // JAMAIS depuis l'input utilisateur
':statut' => $statut
]);
La règle absolue : $_SESSION['entreprise_id'] est toujours défini lors de l'authentification et n'est jamais modifiable par l'utilisateur. Aucun paramètre GET/POST ne peut influencer quel entreprise_id est utilisé dans les requêtes.
Les vecteurs d'attaque inter-tenant les plus courants
1. IDOR (Insecure Direct Object Reference)
L'attaque la plus fréquente sur les SaaS multi-tenant. Un utilisateur accède à /candidat/12345 et remplace l'ID par /candidat/12346 pour voir les données d'un autre client.
Notre défense : chaque endpoint vérifie que l'objet demandé appartient bien à l'entreprise de l'utilisateur connecté :
$candidat = $pdo->prepare(
"SELECT * FROM candidats WHERE id = ? AND entreprise_id = ?"
);
$candidat->execute([$id, $_SESSION['entreprise_id']]);
if (!$candidat->rowCount()) {
http_response_code(403);
exit('Accès interdit');
}
2. Mass assignment
Un utilisateur malveillant envoie un champ entreprise_id dans un formulaire POST pour modifier à quelle entreprise un enregistrement appartient. Notre défense : liste blanche stricte des champs autorisés, jamais d'INSERT INTO table SET ? avec les données brutes du formulaire.
3. Élévation de privilèges via sessions
Après la leçon Snowflake, nous avons renforcé notre gestion des sessions : session_regenerate_id(true) à chaque connexion, expiration de session après 30 minutes d'inactivité, et vérification de l'IP et du User-Agent à chaque requête (invalidation si changement suspect).
Performance avec 50+ tenants sur une instance unique
L'avantage du modèle table partagée : avec des index composites bien conçus, les performances restent excellentes même à grande échelle.
Index critiques dans RecruteX :
CREATE INDEX idx_candidats_tenant ON candidats (entreprise_id, statut, date_creation);
CREATE INDEX idx_offres_tenant ON offres (entreprise_id, actif, date_expiration);
CREATE INDEX idx_candidatures ON offres_candidatures (offre_id, candidat_id, entreprise_id);
Avec ces index, les requêtes filtrées par entreprise_id n'analysent que les lignes du tenant concerné, quelle que soit la taille totale de la table.
Ce que la brèche Snowflake nous a enseigné
L'isolation technique des données ne suffit pas si les credentials sont compromis. Notre liste de défenses complémentaires post-Snowflake :
- Authentification multi-facteurs (TOTP) sur tous les comptes administrateurs RecruteX
- Alertes de connexion depuis une nouvelle IP ou un nouveau pays
- Journalisation de toutes les actions sensibles avec IP, User-Agent et timestamp
- Politique de mots de passe : minimum 12 caractères, renouvellement tous les 90 jours pour les admins
- Pas d'accès direct à la base de données depuis l'extérieur (MySQL bind-address = 127.0.0.1)
Vous développez un SaaS et vous interrogez sur la sécurité de votre architecture multi-tenant ? Contactons-nous — nous proposons des audits d'architecture et des recommandations concrètes.