PmaControl logo PmaControl
  • Accueil
  • PmaControl
    • Agents IA 13 agents on-premise
    • Nos offres Community, Cloud, On-Premise, Premium
    • Documentation Guides, API, architecture
    • Clients 28+ entreprises
    • FAQ 25 questions / 7 catégories
    Bases de données
    • MariaDB 30 articles
    • MySQL 10 articles
    • Galera Cluster 6 articles
    • MaxScale 3 articles
    • ProxySQL 2 articles
    • Amazon Aurora MySQL 0 article
    • Azure Database 0 article
    • ClickHouse 0 article
    • GCP CloudSQL 0 article
    • Percona Server 0 article
    • SingleStore 0 article
    • TiDB 0 article
    • Vitess 0 article
    Solutions
    • Support 24×7 Urgences MariaDB & MySQL
    • Observabilité SQL Monitoring, alertes, topologie
    • Haute disponibilité Réplication, failover, Galera
    • Disaster Recovery Backup, restore, RPO/RTO
    • Sécurité & conformité Audit, RGPD, SOC2
    • Migration & upgrade Zero downtime, pt-osc, gh-ost
  • Nos offres
  • Ressources
    • Documentation Guides techniques & API
    • FAQ 25 questions fréquentes
    • Témoignages Retours clients & cas d'usage
    • Blog Articles & insights
    • Roadmap Fonctionnalités à venir
    Domaines d'expertise
    • Observabilité SQL Monitoring, alertes, topologie Dot3
    • Haute disponibilité Réplication, failover, Galera
    • Sécurité & conformité Audit, RGPD, SOC2, ISO 27001
    • Disaster Recovery Backup, restore, RPO/RTO
    • Performance & optimisation Digests, EXPLAIN, tuning
    • Migration & upgrade Zero downtime, pt-osc
    Liens rapides
    • Wiki GitHub 26 pages — install, engine, plugins
    • Code source Repository GitHub officiel
    • Support 24×7 Urgences MariaDB & MySQL
    • Réserver une démo 30 min — architecture réelle
  • Support 24×7
  • Réserver une démo
Réserver une démo
🇫🇷 FR Français 🇬🇧 EN English 🇵🇱 PL Polski 🇷🇺 RU Русский 🇨🇳 ZH 中文
← Retour au blog

Séparons-nous physiquement

Publié le 4 novembre 2024 Par Sylvain ARBAUDIE
mariadb security access-control views
Partager X LinkedIn Facebook Email PDF
Séparons-nous physiquement

Le modèle AAA appliqué aux bases de données

En sécurité informatique, le modèle AAA (Authentication, Authorization, Accounting) est un pilier fondamental. On le retrouve dans RADIUS, TACACS+, les pare-feu, les VPN... mais rarement appliqué avec rigueur aux bases de données relationnelles.

Pourtant, MariaDB / MySQL offre des mécanismes natifs qui permettent d'implémenter une véritable séparation physique entre les données sensibles et les utilisateurs applicatifs. Pas besoin d'un middleware supplémentaire, pas besoin d'un proxy coûteux. Tout est déjà là, dans le moteur.

L'idée centrale est simple : un utilisateur applicatif ne devrait jamais avoir accès directement aux tables contenant des données sensibles. Il devrait interagir uniquement avec des vues et des procédures stockées soigneusement conçues pour ne lui exposer que le strict nécessaire.

Pourquoi la séparation physique ?

Le modèle classique consiste à donner à l'utilisateur applicatif un GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.*. C'est rapide à mettre en place, mais c'est une catastrophe sécuritaire :

  • L'utilisateur a accès à toutes les colonnes de toutes les tables
  • Une injection SQL dans l'application expose l'intégralité de la base
  • Aucune traçabilité fine des accès aux données sensibles
  • Impossible de masquer certaines colonnes (numéros de carte, emails, mots de passe hashés)

La séparation physique résout ces problèmes en interposant une couche d'abstraction SQL entre l'application et les données.

Étape 1 : Créer un schéma d'interface

CREATE DATABASE app_interface;

Ce schéma ne contiendra aucune table. Uniquement des vues et des procédures stockées. C'est la "surface d'attaque" visible par l'application.

Étape 2 : Créer des vues avec ALGORITHM=TEMPTABLE

La clé de la séparation physique réside dans le choix de l'algorithme de la vue :

CREATE
  ALGORITHM = TEMPTABLE
  DEFINER = 'admin_views'@'localhost'
  SQL SECURITY DEFINER
VIEW app_interface.v_customers AS
SELECT
    customer_id,
    first_name,
    last_name,
    city,
    country
FROM production.customers;

Trois éléments critiques ici :

  • ALGORITHM=TEMPTABLE : MariaDB matérialise la vue dans une table temporaire. L'utilisateur ne peut pas "remonter" à la table sous-jacente via SHOW CREATE VIEW pour construire une requête directe.
  • DEFINER : La vue s'exécute avec les droits du compte admin_views, pas ceux de l'utilisateur applicatif.
  • SQL SECURITY DEFINER : Les vérifications de privilèges sont faites sur le DEFINER, pas sur l'INVOKER. L'utilisateur applicatif n'a besoin de droits que sur la vue, pas sur la table source.

Notez ce qui manque dans la vue : pas d'email, pas de numéro de téléphone, pas d'adresse complète. Le masquage de données est intrinsèque à la conception de la vue.

Étape 3 : Procédures stockées pour les écritures

Pour les opérations d'écriture, les procédures stockées offrent un contrôle encore plus fin :

DELIMITER //
CREATE PROCEDURE app_interface.sp_update_customer_city(
    IN p_customer_id INT,
    IN p_city VARCHAR(100)
)
SQL SECURITY DEFINER
BEGIN
    -- Validation métier
    IF p_city IS NULL OR LENGTH(TRIM(p_city)) = 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'City cannot be empty';
    END IF;

    UPDATE production.customers
    SET city = p_city,
        updated_at = NOW()
    WHERE customer_id = p_customer_id;

    -- Audit trail
    INSERT INTO production.audit_log(
        table_name, record_id, field_name,
        action, performed_by, performed_at
    )
    VALUES (
        'customers', p_customer_id, 'city',
        'UPDATE', CURRENT_USER(), NOW()
    );
END //
DELIMITER ;

L'utilisateur applicatif ne peut modifier que la ville. Pas le nom, pas l'email, pas le statut du compte. Et chaque modification est auditée automatiquement.

Étape 4 : Le compte administrateur verrouillé

Le compte DEFINER des vues et procédures ne doit jamais être utilisé pour se connecter :

CREATE USER 'admin_views'@'localhost'
    IDENTIFIED BY 'impossible_to_guess_random_string';

GRANT SELECT, INSERT, UPDATE ON production.* TO 'admin_views'@'localhost';

ALTER USER 'admin_views'@'localhost' ACCOUNT LOCK;

Un compte verrouillé (ACCOUNT LOCK) ne peut pas se connecter, mais ses privilèges restent actifs pour les vues et procédures en mode SQL SECURITY DEFINER. C'est le point crucial de l'architecture : le compte qui a les droits ne peut pas se connecter, et le compte qui se connecte n'a pas les droits directs.

Étape 5 : L'utilisateur applicatif minimal

CREATE USER 'app_user'@'10.0.%'
    IDENTIFIED BY 'strong_password_here';

GRANT SELECT ON app_interface.v_customers TO 'app_user'@'10.0.%';
GRANT EXECUTE ON PROCEDURE app_interface.sp_update_customer_city
    TO 'app_user'@'10.0.%';

-- Aucun GRANT sur production.*

L'utilisateur applicatif n'a accès à rien dans le schéma production. Même en cas d'injection SQL réussie, l'attaquant ne peut voir que les données exposées par les vues et ne peut exécuter que les procédures autorisées.

Masquage de données avancé

Les vues permettent aussi des techniques de masquage sophistiquées :

CREATE VIEW app_interface.v_customer_contacts AS
SELECT
    customer_id,
    CONCAT(LEFT(email, 3), '***@***.',
           SUBSTRING_INDEX(email, '.', -1)) AS masked_email,
    CONCAT('***-***-', RIGHT(phone, 4)) AS masked_phone
FROM production.customers;

Le support client peut identifier un client par les 4 derniers chiffres de son téléphone sans jamais voir le numéro complet.

Limitation du débit par requête

Une technique souvent négligée : utiliser les procédures stockées pour implémenter un rate limiting au niveau de la base :

CREATE PROCEDURE app_interface.sp_search_customers(
    IN p_search_term VARCHAR(100)
)
SQL SECURITY DEFINER
BEGIN
    DECLARE v_count INT;

    SELECT COUNT(*) INTO v_count
    FROM production.rate_limit
    WHERE user = CURRENT_USER()
      AND action = 'search'
      AND created_at > NOW() - INTERVAL 1 MINUTE;

    IF v_count > 10 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Rate limit exceeded: max 10 searches/minute';
    END IF;

    INSERT INTO production.rate_limit(user, action, created_at)
    VALUES (CURRENT_USER(), 'search', NOW());

    SELECT customer_id, first_name, last_name, city
    FROM production.customers
    WHERE last_name LIKE CONCAT(p_search_term, '%')
    LIMIT 50;
END;

Récapitulatif de l'architecture

Couche Composant Rôle
Application app_user Se connecte, exécute des vues/procédures
Interface app_interface (schéma) Expose uniquement les données nécessaires
Sécurité admin_views (verrouillé) Détient les droits, ne peut pas se connecter
Production production (schéma) Tables réelles, inaccessibles directement

Les limites

Cette approche n'est pas parfaite :

  • Performance : ALGORITHM=TEMPTABLE crée une copie temporaire. Pour les grosses tables, cela peut être coûteux.
  • Complexité : Chaque nouvelle fonctionnalité applicative nécessite potentiellement une nouvelle vue ou procédure.
  • Maintenance : Les vues doivent évoluer avec le schéma des tables sous-jacentes.

Mais ces contraintes sont le prix de la sécurité. Et dans un contexte où les fuites de données coûtent en moyenne 4,5 millions de dollars par incident, c'est un investissement raisonnable.

Conclusion

La séparation physique via les vues TEMPTABLE et les procédures stockées DEFINER n'est pas une fonctionnalité obscure de MariaDB / MySQL. C'est une architecture de sécurité robuste, native, et souvent sous-exploitée.

Cinq étapes suffisent : un schéma d'interface, des vues avec le bon algorithme, des procédures pour les écritures, un compte DEFINER verrouillé, et un utilisateur applicatif minimal. Le résultat est une base de données où même une injection SQL réussie ne donne accès qu'à une fraction contrôlée des données.


Cet article a été initialement publié sur Medium.

Partager X LinkedIn Facebook Email PDF
← Retour au blog

Commentaires (0)

Aucun commentaire pour le moment.

Laisser un commentaire

PmaControl
+33 6 63 28 27 47 contact@pmacontrol.com
Mentions légales GitHub Contact
N'attendez pas l'incident pour comprendre votre architecture. © 2014-2026 PmaControl — 68Koncept