# Vues de masquage

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

---

Index LLMS : [llms.txt](/fr/llms.txt)

---

<!-- Source: https://public.dalibo.com/exports/formation/manuels/formations/dev42/dev42.handout.html, révision 26.09. -->

# Vues de masquage {#dev42-ch15}

## Principe {#dev42-ch15-1}

- 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 {#dev42-ch15-1-1}

- Flouter les données
- Par ex : 25 juillet 1989 <span class="math inline">⇒</span> 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 {#dev42-ch15-2}

- 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 ? {#dev42-ch15-3}

![Illustration du manuel DEV42](/images/dev42/html/ch15-52fd7b990a0e.png)

## Objectifs {#dev42-ch15-4}

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 » {#dev42-ch15-5}

``` sql
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 {#dev42-ch15-6}

``` bash
curl -Ls https://dali.bo/employee -o /tmp/employee.tsv
```

``` sql
\c boutique paul
\COPY employee FROM '/tmp/employee.tsv'
```

Ce fichier charge 16 lignes, dont :

``` sql
SELECT full_name,first_day, hair, size, asthma
FROM employee
LIMIT 3 ;
```

``` default
  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 {#dev42-ch15-7}

Pierre peut trouver un lien entre asthme et yeux verts :

``` sql
\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 :

``` sql
SELECT *
FROM v_asthma_eyes
LIMIT 3;
```

``` default
 eyes  | asthma
-------+--------
 blue  | t
 brown | f
 blue  | t
```

``` sql
SELECT
  eyes,
  100*COUNT(1) FILTER (WHERE asthma) / COUNT(1) AS asthma_rate
FROM v_asthma_eyes
GROUP BY eyes ;
```

``` default
 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 {#dev42-ch15-8}

- Les colonnes `asthma` et `eyes` sont considérés comme des identifiants indirects.

``` sql
\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';
```

``` sql
SELECT anon.k_anonymity('v_asthma_eyes');
```

``` sql
SELECT anon.k_anonymity('v_asthma_eyes');
```

``` default
 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](https://en.wikipedia.org/wiki/K-anonymity).

> Le fournisseur est ici `k-anonymity` et plus `anon` !

## Fonctions d’intervalle et de généralisation {#dev42-ch15-9}

``` sql
\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 ;
```

``` sql
\c boutique pierre
SELECT *
FROM v_staff_per_month
LIMIT 3;
```

``` default
        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 :

``` sql
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 ;
```

``` default
 count
-------
     4
```

### Déclarer les identifiants indirects {#dev42-ch15-9-1}

Calculer le facteur de *k*-anonymat de cette vue :

``` sql
\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';
```

``` sql
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 {#dev42-ch15-10}

### E401 - Simplifier la vue v_staff_per_month pour en réduire la granularité. {#dev42-ch15-10-1}

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 {#dev42-ch15-10-2}

- 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 {#dev42-ch15-10-3}

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

## Solutions {#dev42-ch15-11}

### S401 {#dev42-ch15-11-1}

- É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 :

``` sql
\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;
```

``` sql
SELECT *
FROM v_staff_per_year
LIMIT 3;
```

``` default
   period
-------------
 [2018,2019)
 [2020,)
 [2018,2019)
```

### S402 {#dev42-ch15-11-2}

- 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 :

``` sql
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;
```

``` default
 year | count
------+-------
 2018 |     4
 2019 |     6
 2020 |     9
 2021 |    10
```

### S403 {#dev42-ch15-11-3}

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

Le k-anonymat de cette vue est meilleur :

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

SELECT anon.k_anonymity('v_staff_per_year');
```

``` default
 k_anonymity
-------------
           2
```
## Navigation

Pour revenir au chapitre précédent, voir [le chapitre précédent](/fr/dev42/14-sauvegardes-anonymes/#dev42-ch14).
Pour poursuivre la lecture, voir [le chapitre suivant](/fr/dev42/16-replica-anonymise/#dev42-ch16).
