Aller au contenu

15 Vues de masquage

Transcription française complète du chapitre « Vues de masquage » du manuel DEV42, révision 26.09, pages PDF 533 à 546.
DEV42

Vues de masquage

Principe

  • Les vues de masquage permettent de modifier le type de données
  • Similaire au masquage dynamique
  • Très utiles pour mettre en place de la généralisation

Généralisation

  • Flouter les données
  • Par ex : 25 juillet 1989 ⇒ années 1980

L’idée derrière la généralisation est de pouvoir flouter une donnée originale.

Par exemple, au lieu de dire « Monsieur X est né le 25 juillet 1989 », on peut dire « Monsieur X est né dans les années 1980 ». L’information reste vraie, bien que moins précise, et elle rend plus difficile l’identification de la personne.

L’histoire

  • Paul a embauché des dizaines de salariés au fil du temps.

  • Il conserve une trace sur la couleur de leurs cheveux, leurs tailles, et leurs conditions médicales.

  • Paul souhaite extraire des statistiques depuis ces détails.

  • Il fournit des vues généralisées à Pierre.

Comment ça marche ?

Illustration du manuel DEV42

Objectifs

Nous allons voir :

  • la différence entre le masquage dynamique et les vues de masquage
  • un exemple de généralisation
  • le concept de « k-anonymat »

Table « employee »

DROP TABLE IF EXISTS employee CASCADE;
CREATE TABLE employee (
  id INT PRIMARY KEY,
  full_name  TEXT,
  first_day DATE, last_day DATE,
  height INT,
  hair TEXT, eyes TEXT, size TEXT,
  asthma BOOLEAN,
  CHECK(hair = ANY(ARRAY['bald','blond','dark','red'])),
  CHECK(eyes = ANY(ARRAY['blue','green','brown'])) ,
  CHECK(size = ANY(ARRAY['S','M','L','XL','XXL']))
);
  • Légal ?

Bien sûr, stocker les caractéristiques physiques d’employés est généralement illégal. Quoi qu’il en soit, il sera impératif de les masquer.

Quelques données

curl -Ls https://dali.bo/employee -o /tmp/employee.tsv
\c boutique paul
\COPY employee FROM '/tmp/employee.tsv'

Ce fichier charge 16 lignes, dont :

SELECT full_name,first_day, hair, size, asthma
FROM employee
LIMIT 3 ;
  full_name   | first_day  | hair  | size | asthma
--------------+------------+-------+------+--------
 Luna Dickens | 2018-07-22 | blond | L    | t
 Paul Wolf    | 2020-01-15 | bald  | M    | f
 Rowan Hoeger | 2018-12-01 | dark  | XXL  | t

Suppression de données

Pierre peut trouver un lien entre asthme et yeux verts :

\c boutique paul
DROP MATERIALIZED VIEW IF EXISTS v_asthma_eyes ;

CREATE MATERIALIZED VIEW v_asthma_eyes AS
SELECT eyes, asthma
FROM employee ;

Paul souhaite savoir s’il y a une corrélation entre l’asthme et la couleur des yeux.

Il fournit à Pierre la vue ci-dessus, qui peut désormais écrire des requêtes sur cette vue :

SELECT *
FROM v_asthma_eyes
LIMIT 3;
 eyes  | asthma
-------+--------
 blue  | t
 brown | f
 blue  | t
SELECT
  eyes,
  100*COUNT(1) FILTER (WHERE asthma) / COUNT(1) AS asthma_rate
FROM v_asthma_eyes
GROUP BY eyes ;
 eyes  | asthma_rate
-------+-------------
 green |         100
 brown |          37
 blue  |          33

Paul vient de prouver que l’asthme est favorisé par les yeux verts, et surtout de trouver une corrélation entre deux champs.

Calculer le k-anonymat

  • Les colonnes asthma et eyes sont considérés comme des identifiants indirects.
\c boutique paul
SECURITY LABEL FOR k_anonymity ON COLUMN v_asthma_eyes.eyes
IS 'INDIRECT IDENTIFIER';

SECURITY LABEL FOR k_anonymity ON COLUMN v_asthma_eyes.asthma
IS 'INDIRECT IDENTIFIER';
SELECT anon.k_anonymity('v_asthma_eyes');
SELECT anon.k_anonymity('v_asthma_eyes');
 k_anonymity
-------------
           2

La vue v_asthma_eyes a le niveau « 2-anonymity ». Cela signifie que chaque combinaison de quasi-identifiants (eyes-asthma) apparaît au moins 2 fois dans le jeu de données.

En d’autres termes, cela veut dire qu’un individu ne peut pas être distingué d’au moins un autre individu (k-1) dans cette vue.

Pour les détails sur le K-anonymat, voir cet article sur Wikipédia.

Le fournisseur est ici k-anonymity et plus anon !

Fonctions d’intervalle et de généralisation

\c boutique paul
DROP MATERIALIZED VIEW IF EXISTS v_staff_per_month ;

CREATE MATERIALIZED VIEW v_staff_per_month AS
SELECT
    anon.generalize_daterange(first_day,'month') AS first_day,
    anon.generalize_daterange(last_day, 'month') AS last_day
FROM employee ;

GRANT SELECT ON v_staff_per_month TO pierre ;
\c boutique pierre
SELECT *
FROM v_staff_per_month
LIMIT 3;
        first_day        |        last_day
-------------------------+-------------------------
 [2018-07-01,2018-08-01) | [2018-12-01,2019-01-01)
 [2020-01-01,2020-02-01) | (,)
 [2018-12-01,2019-01-01) | [2018-12-01,2019-01-01)

Pierre peut écrire une requête pour trouver le nombre d’employés embauchés en novembre 2021 :

SELECT COUNT(1)
       FILTER (
            WHERE make_date(2019,11,1)
            BETWEEN lower(first_day)
            AND COALESCE(upper(last_day),now())
       )
FROM v_staff_per_month ;
 count
-------
     4

Déclarer les identifiants indirects

Calculer le facteur de k-anonymat de cette vue :

\c boutique paul
SECURITY LABEL FOR k_anonymity ON COLUMN v_staff_per_month.first_day
IS 'INDIRECT IDENTIFIER';
SECURITY LABEL FOR k_anonymity ON COLUMN v_staff_per_month.last_day
IS 'INDIRECT IDENTIFIER';
SELECT anon.k_anonymity('v_staff_per_month');

Dans ce cas, le résultat est 1, ce qui veut dire qu’au moins une personne peut être directement identifiée par les dates de ses premier et dernier jour en poste.

Dans ce cas, la généralisation est insuffisante.

Exercices

E401 - Simplifier la vue v_staff_per_month pour en réduire la granularité.

Généraliser les dates en mois n’est pas suffisant. - Écrire une autre vue - v_staff_per_year qui va généraliser les dates en années. - Simplifier également la vue en utilisant un intervalle de int pour stocker - l’année, plutôt qu’un intervalle de date.

E402 - Progression du personnel au fil des années

  • Combien de personnes ont travaillé pour Paul chaque année entre 2018 et 2021 ?

E403 - Atteindre le facteur 2-anonymity sur la vue v_staff_per_year

  • Quel est le facteur k-anonymat de la vue v_staff_per_year ?

Solutions

S401

  • Écrire une autre vue
  • v_staff_per_year qui va généraliser les dates en années.
  • Simplifier également la vue en utilisant un intervalle de int pour stocker
  • l’année, plutôt qu’un intervalle de date.

Cette vue généralise les dates en années :

\c boutique paul
DROP MATERIALIZED VIEW IF EXISTS v_staff_per_year;
CREATE MATERIALIZED VIEW v_staff_per_year AS
SELECT
  int4range(
    extract(year from first_day)::INT,
    extract(year from last_day)::INT,
    '[]' -- include upper bound
  ) AS period
FROM employee;
SELECT *
FROM v_staff_per_year
LIMIT 3;
   period
-------------
 [2018,2019)
 [2020,)
 [2018,2019)

S402

  • Combien de personnes ont travaillé pour Paul chaque année entre 2018 et 2021 ?

Les personnes ayant travaillé pour Paul entre 2018 et 2021 sont :

SELECT
  year,
  COUNT(1) FILTER (
      WHERE year <@ period
  )
FROM
    generate_series(2018,2021) year,
    v_staff_per_year
GROUP BY year
ORDER BY year ASC;
 year | count
------+-------
 2018 |     4
 2019 |     6
 2020 |     9
 2021 |    10

S403

  • Quel est le facteur k-anonymat de la vue v_staff_per_year ?

Le k-anonymat de cette vue est meilleur :

SECURITY LABEL FOR k_anonymity ON COLUMN v_staff_per_year.period
IS 'INDIRECT IDENTIFIER';

SELECT anon.k_anonymity('v_staff_per_year');
 k_anonymity
-------------
           2

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