Aller au contenu

12 Masquage statique

Transcription française complète du chapitre « Masquage statique » du manuel DEV42, révision 26.09, pages PDF 489 à 504.
DEV42

Masquage statique

  • Le plus simple
  • Destructif

Le masquage statique est la méthode la plus simple pour cacher des données personnelles. L’idée est simplement de détruire les données originales et de les remplacer par des données artificielles.

L’histoire

  • Au fil des années, Paul a accumulé des données sur ses clients et leurs achats dans une base de données très simple.

  • Il a récemment installé un nouveau logiciel de ventes, et l’ancienne base est obsolète.

  • Avant de l’archiver, il voudrait en supprimer toutes les données personnelles.

Comment ça marche ?

Illustration du manuel DEV42

Objectifs

Nous allons voir :

  • comment écrire des règles de masquage simples
  • les intérêts et limitations du masquage statique
  • le concept de « singularisation » d’une personne (singling out)

Table « customer »

\c boutique paul
DROP TABLE IF EXISTS customer CASCADE;
DROP TABLE IF EXISTS payout CASCADE;

CREATE TABLE customer (
    id SERIAL PRIMARY KEY,
    firstname TEXT,
    lastname TEXT,
    phone TEXT,
    birth DATE,
    postcode TEXT
);

Quelques clients

Insertion de quelques personnes :

INSERT INTO customer
VALUES
(107,'Sarah','Conor','060-911-0911', '1965-10-10', '90016'),
(258,'Luke', 'Skywalker', NULL, '1951-09-25', '90120'),
(341,'Don', 'Draper','347-515-3423', '1926-06-01', '04520')
;
SELECT * FROM customer;
 id  | firstname | lastname  |    phone     |   birth    | postcode
-----+-----------+-----------+--------------+------------+----------
 107 | Sarah     | Conor     | 060-911-0911 | 1965-10-10 | 90016
 258 | Luke      | Skywalker |              | 1951-09-25 | 90120
 341 | Don       | Draper    | 347-515-3423 | 1926-06-01 | 04520
(3 lignes)

Table « payout »

Les ventes sont suivies dans cette simple table :

CREATE TABLE payout (
    id SERIAL PRIMARY KEY,
    fk_customer_id INT REFERENCES customer(id),
    order_date DATE,
    payment_date DATE,
    amount INT
);

Quelques données

Quelques commandes :

INSERT INTO payout
VALUES
(1,107,'2021-10-01','2021-10-01', '7'),
(2,258,'2021-10-02','2021-10-03', '20'),
(3,341,'2021-10-02','2021-10-02', '543'),
(4,258,'2021-10-05','2021-10-05', '12'),
(5,258,'2021-10-06','2021-10-06', '92')
;

Déclarer et appliquer les règles de masquage

Pour le masquage statique, deux étapes :

  1. Déclaration des règles de masquage (SECURITY LABEL);
  2. Application des règles de masquage.

Pour le masquage statique, la déclaration des règles de masquage est à faire avant leur application. Cette déclaration passe par la création de SECURITY LABEL.

Le masquage statique est exécuté par les fonctions anon.anonymize_table() et anon.anonymize_column()

Déclarer les règles de masquage

SECURITY LABEL FOR anon ON COLUMN customer.lastname
IS 'MASKED WITH FUNCTION anon.dummy_last_name()';

SECURITY LABEL FOR anon ON COLUMN customer.phone
IS 'MASKED WITH FUNCTION anon.partial(phone,2,$$X-XXX-XX$$,2)';

Dans cet exemple, Paul veut masquer le nom de famille et le numéro de téléphone de ses clients.

Pour cela, il utilise les fonctions dummy_last_name() et partial().

Appliquer les règles de manière permanente

Application des règles de masquage :

SELECT anon.anonymize_table('customer');

Cette fonction ne fait qu’appliquer la règle et doit renvoyer True. Ensuite :

SELECT id, firstname, lastname, phone
FROM customer;
 id  | firstname | lastname |    phone
-----+-----------+----------+--------------
 107 | Sarah     | Okuneva  | 06X-XXX-XX11
 258 | Luke      | Okuneva  |
 341 | Don       | Boyle    | 34X-XXX-XX23

Cette technique est nommée « masquage statique » car la donnée réelle a été détruite de manière définitive. L’anonymisation dynamique et les exports seront vus plus loin.

Gestion des SECURITY LABEL

  • Obtenir la liste des labels :
SELECT pg_class.relname AS table, pg_seclabel.label
FROM pg_seclabel INNER JOIN pg_class ON pg_seclabel.objoid = pg_class.oid
WHERE provider = 'anon';
  • Suppression d’un label :
SECURITY LABEL FOR anon ON COLUMN <table>.<colonne> IS NULL;

Les règles de masquage passent systématiquement par des SECURITY LABEL définis pour le schéma anon.

En cas d’erreur lors de la déclaration d’une fonction de masquage, il n’y a pas d’autre solution que de supprimer et de recréer le label.

Exercices

E101 - Masquer les prénoms des clients

  • Déclarer une nouvelle règle de masquage et relancer l’anonymisation statique.

E102 - Masquer les 3 derniers chiffres du code postal

Paul réalise que le code postal est un bon indice sur l’endroit où vivent ses clients. Cependant, il voudrait pouvoir faire des statistiques par département.

  • Créer une règle de masquage pour remplacer les 3 derniers chiffres du code postal par ‘x’.

E103 - Compter le nombre de clients dans chaque département.

  • Agréger les clients selon le code postal anonymisé.

E104 - Ne garder que l’année dans les dates de naissance

Paul veut des statistiques selon l’âge. Mais il veut aussi masquer les vraies dates de naissance de ses clients.

  • Remplacer toutes les dates de naissance par le 1er janvier, en conservant l’année réelle. \
  • Utiliser la fonction date_trunc.

E105 - Identifier un client particulier

Même si un client est correctement anonymisé, il est possible d’isoler un individu grâce à des données d’autres tables. Par exemple, il est possible d’identifier le meilleur client de Paul avec une telle requête :

WITH best_client AS (
    SELECT SUM(amount), fk_customer_id
    FROM payout
    GROUP BY fk_customer_id
    ORDER BY 1 DESC
    LIMIT 1
)
SELECT c.*
FROM customer c
JOIN best_client b ON (c.id = b.fk_customer_id) ;
 id  | firstname | lastname |    phone     |   birth    | postcode
-----+-----------+----------+--------------+------------+----------
 341 | Don       | Boyle    | 34X-XXX-XX23 | 1926-06-01 | 04520

Ce processus est appelé « singularisation » (singling out) d’une personne.

Il faut donc aller plus loin dans l’anonymisation, en supprimant le lien entre une personne et sa société. Dans la table des commandes order, ce lien est matérialisé par une clé étrangère sur le champ fk_company_id. Mais nous ne pouvons supprimer des valeurs de cette colonne ou y insérer de faux identifiants, car cela briserait la contrainte de clé étrangère.

Comment séparer les clients de leurs paiements tout en respectant l’intégrité des données ?

  • Trouver une fonction qui mélange les valeurs de fk_company_id dans la table payout.\
  • Consulter la section shuffling de la documentation.

Solutions

S101

  • Déclarer une nouvelle règle de masquage et relancer l’anonymisation statique.
SECURITY LABEL FOR anon ON COLUMN customer.firstname
IS 'MASKED WITH FUNCTION anon.dummy_first_name()' ;

SELECT anon.anonymize_table('customer') ;

La table anonymisée devient :

SELECT id, firstname, lastname
FROM customer ;
 id  | firstname | lastname
-----+-----------+----------
 107 | Hans       | Barton
 258 | Jacqueline | Dare
 341 | Sibyl      | Runte

S102

  • Créer une règle de masquage pour remplacer les 3 derniers chiffres du code postal par ‘x’.
SECURITY LABEL FOR anon ON COLUMN customer.postcode
IS 'MASKED WITH FUNCTION anon.partial(postcode,2,$$xxx$$,0)' ;

SELECT anon.anonymize_table('customer') ;

Le code postal anonymisé devient :

SELECT id, firstname, lastname, postcode
FROM customer ;
 id  | firstname | lastname | postcode
-----+-----------+----------+----------
 107 | Curt      | O'Hara   | 90xxx
 258 | Agusta    | Towne    | 90xxx
 341 | Sid       | Hane     | 04xxx

Noter que les noms ont encore changé après application de anon.anonymize_table().

S103

  • Agréger les clients selon le code postal anonymisé.
SELECT postcode, COUNT(id)
FROM customer
GROUP BY postcode;
 postcode | count
----------+-------
 90xxx    |     2
 04xxx    |     1

S104

  • Remplacer toutes les dates de naissance par le 1er janvier, en conservant l’année réelle. \
  • Utiliser la fonction date_trunc.
SECURITY LABEL FOR anon ON FUNCTION pg_catalog.date_trunc(text,interval) IS 'TRUSTED';

SECURITY LABEL FOR anon ON COLUMN customer.birth IS
$$ MASKED WITH FUNCTION pg_catalog.date_trunc('year',birth) $$;

SELECT anon.anonymize_table('customer');

Les dates de naissance anonymisées deviennent :

SELECT id, firstname, lastname, birth
FROM customer ;
 id  | firstname | lastname |   birth
-----+-----------+----------+------------
 107 | Pinkie    | Sporer   | 1965-01-01
 258 | Zebulon   | Gerlach  | 1951-01-01
 341 | Erna      | Emmerich | 1926-01-01

S105

  • Trouver une fonction qui mélange les valeurs de fk_company_id dans la table payout.\
  • Consulter la section shuffling de la documentation.

Pour mélanger les valeurs de fk_customer_id :

SELECT anon.shuffle_column('payout','fk_customer_id','id') ;

Si l’on essaie à nouveau d’identifier le meilleur client :

WITH best_client AS (
    SELECT SUM(amount), fk_customer_id
    FROM payout
    GROUP BY fk_customer_id
    ORDER BY 1 DESC
    LIMIT 1
)
SELECT c.*
FROM customer c
JOIN best_client b ON (c.id = b.fk_customer_id) ;
 id  | firstname | lastname | phone |   birth    | postcode
-----+-----------+----------+-------+------------+----------
 258 | Zebulon   | Gerlach  |       | 1951-01-01 | 90xxx

Noter que le lien entre un client (customer) et ses paiements (payout) est à présent complètement faux !

Par exemple, si un client A a deux paiements, l’un se retrouvera associé à un client B, et l’autre à un client C. En d’autres termes, cette méthode de mélange respectera la contrainte d’intégrité technique, mais brisera l’intégrité des données. Pour certaines utilisations, ce peut être problématique.

Ici, Pierre ne pourra pas produire de rapport avec les données mélangées.

Pour revenir au chapitre précédent, voir le chapitre précédent. Pour poursuivre la lecture, voir le chapitre suivant.