Analyse de risque des statistiques TousAntiCovid
Analyse de risque des statistiques TousAntiCovid
Auteurs:
- Johan D., https://twitter.com/JohanD_0
- Nils L., https://twitter.com/gilbsgilbs, gilbsgilbs@pm.me
- Gaëtan Leurent, https://twitter.com/cryptosaurus6, gaetan.leurent@inria.fr
Depuis juin, l'application TousAntiCovid intègre un système permettant de générer des statistiques sur l'utilisation de l'application (télémétrie/analytics). Cela devrait permettre d'évaluer son utilisation et son efficacité, mais aucune statistique n'a été publiée après plus de deux mois d'utilisation (on ne sait toujours pas combien il y a d'utilisateurs de l'application !).
Malheureusement, la collecte de statistiques contredit le principe de minimisation des données et met en danger les propriétés de sécurité et de protection de la vie privée offertes par les protocoles de traçage de contact ROBERT (traçage Bluetooth) et Cléa (traçage par QR-codes de lieux). En effet, les statistiques incluent un journal d'événement très détaillé, qui enregistre la plupart des actions faites par l'utilisateur, avec un horodatage précis. Nous avons identifié plusieurs façons de réduire les garanties de sécurité de l'application en utilisant les statistiques envoyées. Le serveur central peut notamment:
- Mettre en correspondance les différentes sources de données qui devraient être indépendantes
- Identifier certains utilisateurs
- Récupérer des informations sur la vie privée de certains utilisateurs (test positif, status vaccinal, relations sociales)
Enfin, ce système de collecte est activé par défaut, le consentement de l'utilisateur n'est pas demandé et la politique de confidentialité de l'application n'indique pas la nature exacte et réelle du traitement.
Plan
- Analyse de risque des statistiques TousAntiCovid
Remarque: ce rapport parle principalement des fonctionnalités de traçage de contact de TousAntiCovid. En particulier, il y a deux types de QR-code utilisés:
- les QR-codes de lieux qui remplacent les carnets de rappel papier depuis le 9 juin (fonctionnalité TAC-Signal, protocole Cléa)
- les QR-codes correspondant au pass sanitiares.
Ce document fait fait principalement référence aux QR-codes de lieux.
Objectifs de sécurité des protocoles ROBERT et Cléa
TousAntiCovid utilise des protocoles construits selon le principe de "privacy by design" et de minimisation des données:
- le protocole ROBERT pour le traçage de contact Bluetooth: https://github.com/ROBERT-proximity-tracing/
- le protocole Cléa pour le traçage de contact par QR-codes dans les lieux publics: https://hal.inria.fr/hal-03146022v2
L'objectif de ces protocoles est de protéger la vie privée des utilisateurs même si le serveur central est malveillant, comme résumé par Bruno Sportisse (PDG de Inria):
Sa conception permet que PERSONNE, pas même l’Etat, n’ait accès à la liste des personnes diagnostiquées positives ou à la liste des interactions sociales entre les personnes.
Ces hypothèses sont clairement décrites dans la spécification de ROBERT
Cléa offre aussi de très bonnes garanties en termes de vie privée: aucune donnée n'est envoyée à un serveur tant que l'utilisateur ne s'est pas déclaré positif au Covid-19:
Notre analyse montre que la collecte de statistiques viole ces garanties de sécurité, et TousAntiCovid offre maintenant une sécurité très faible contre un serveur qui essaye d'identifier les utilisateurs.
Problèmes déjà connus
Avant de parler des analytics, il faut signaler que le serveur peut déjà essayer d'identifier les utilisateurs à partir de leur adresse IP. La spécification ROBERT prévoyait de mettre en place un mixnet pour protéger les utilisateurs, mais cela n'a, à ce jour, pas été implémenté: robert-server#31
Description technique des analytics
Le système de télémétrie envoie deux types de données, comme expliqué dans l'AIPD (version datée du 21 avril 2021) :
- des statistiques liées à l'identifiant de l'application
- des statistiques sans identifiant pérenne qui contiennent des données plus sensibles (en particulier données de santé)
En réalité, les deux jeux de statistiques comportent d'une part des données générales comme indiquées dans l'AIPD, et d'autre part un journal d'événements, avec un horodatage très précis. Les données sont envoyées à une fréquence régulière (actuellement toutes les 12 heures). Dans cette section, nous détaillons les données envoyées, mais le lecteur peut passer directement à l'analyse de risques sans avoir besoin des détails techniques.
Statistiques liées à l'identifiant de l'application
Les statistiques liées à l'identifiant de l'application sont envoyées par la fonction sendAppAnalytics
. Il y a trois types de données:
-
Des statistiques générales (structure AppInfo):
-
appBuild
: Version de l'application (numéro de version interne) -
appVersion
: Version de l'application -
certificatesCount
: Nombre de certificats ajoutés dans le wallet -
deviceModel
: Modèle de téléphone -
formsCount
: Nombre d'attestations de déplacement génerées -
os
: Système d'exploitation (iOS ou Android) -
osVersion
: Version du système d'exploitation -
placesCount
: Nombre de lieux où un QR-Code a été scanné (Cléa) -
receivedHelloMessagesCount
: Nombre de messages Bluetooth reçus d'autres appareils à proximité (ROBERT) -
statusSuccessCount
: Nombre de synchronisations réussies -
type
: 0 pour ces requêtes -
userHasAZipcode
: Si l'utilisateur a indiqué un code postal (vrai/faux) -
installationUuid
: Identifiant de l'installation (UUID
constant pour toutes les requêtes de ce type)
-
-
Un journal d'événements.
À ce jour, il n'y a aucune documentation officielle des événements envoyés par l'application, on retrouve uniquement des codes numériques. Pour comprendre à quoi correspondent ces événements, nous avons analysé le code source et le comportement des applications Android et iOS pour retrouver les déclencheurs et ainsi comprendre le sens de chaque type d'événement. Au total, il y a 21 types d'événements applicatifs possibles:
-
e1
: Declenché lors de l'ouverture de l'application suite à un clic sur une notification (uniquement sur iOS) -
e2
: Modification du niveau de risque calculé avec notification / alerte -
e3
: Declenché lorsque l'application revient au premier plan -
e4
: Lors du clic sur le bouton "Partager TousAntiCovid" -
e5
: Affichage de la vue "Ma santé" -
e6
: Affichage du formulaire "Dois-je m'isoler" -
e7
: Affichage de la vue "Je me fais vacciner" -
e8
: Affichage des chiffres clés -
e9
: Affichage du détail d'un chiffre clé -
e10
: Affichage des actualités -
e11
: Affichage des attestations -
e12
: Affichage du cahier de rappel -
e13
: Déclenché lors de l'ajout d'un certificat (2D-DOC ou pass européen) dans le carnet -
e14
: Déclenché lors de l'ajout d'un lieu visité -
e15
: Déclenché après le retour de la synchronisation Cléa OK -
e16
: Déclenché après le retour de la synchronisation ROBERT OK -
e17
: Déclenché lors du clic sur le bouton "Supprimer mes données" dans les paramètres de l'application -
e18
: Déclenché lors du clic sur le bouton "Scanner un QR-Code" sur l'accueil -
e19
: Déclenché lors du clic sur le bouton "Scanner un QR-Code" sur l'accueil (uniquement sur iOS) -
e20
: Déclenché avant l'envoi de la requête de conversion 2D-Doc -> DCC -
e21
: Déclenché après le retour de la requête de conversion 2D-Doc -> DCC OK
Ces événements sont transmis au serveur avec un timestamp (horodatage) précis à la milliseconde (Exemple:
2021-08-12T23:42:48.988Z
). -
-
Un journal d'erreurs survenues pendant le fonctionnement de l'application. Il n'y a pas non plus de documentation explicite sur la nature précise de ces erreurs, mais une étude du code permet de constater qu'il s'agit seulement d'erreurs inattendues consécutives à des problèmes de communication de l'application TousAntiCovid avec ses différentes APIs (ROBERT Proximity Tracing, CLÉA, backend de conversion 2D-DOC, service de CAPTCHA et analytics) et à des problèmes de traitement des réponses de ces APIs.
Ces erreurs sont représentées par plusieurs champs qui sont envoyés au serveur d'analytics:
-
timestamp
: Un horodatage précis à la milliseconde, correspondant au moment où l'erreur s'est produite -
name
: Une chaîne de caractères formatée de la façon suivanteERR-{nom du service}-{version de l'API invoquée}-{code d'erreur HTTP}
- Le nom du service est sélectionné dans
AnalyticsServiceName
- Le code d'erreur HTTP vaut
0
si l'erreur n'est pas une erreur HTTP (e.g. erreur réseau ou erreur dans le traitement de la réponse)
- Le nom du service est sélectionné dans
-
desc
: Une description optionnelle sous la forme d'une chaine de caractères définie arbitrairement pour l'erreur. Cette description est généralement remplie avec le message de l'exception sous-jacente.
-
Statistiques non liées à un identifiant à long terme
Les autres statistiques sont liées à un identifiant généré aléatoirement à chaque appel. Elles sont envoyées par la fonction sendHealthAnalytics
, et suivent le même modèle, avec deux types de données:
-
Des statistiques générales (structure HealthInfo):
-
os
: Système d'exploitation (iOS ou Android) -
riskLevel
: Niveau de risque calculé par le traçage de contact -
secondsTracingActivated
: Durée pendant laquelle l'utilisateur a activé la fonction de traçage Bluetooth (ROBERT) -
dateSample
: Date du test positif (si l'utilisateur a déclaré un test positif) -
dateFirstSymptoms
: Date de premiers symptômes (si l'utilisateur a déclaré un test positif) -
dateLastContactNotification
: Date approximative du dernier contact à risque -
type
: 1 pour ces requêtes -
installationUuid
: Identifiant aléatoire différent à chaque requête
-
-
Un journal d'événements. Il y a 2 types d'événements de santé possibles:
-
eh1
: Déclenché lorsque l'utilisateur se déclare positif (avec un QR-Code de déclaration ou un code court) -
eh2
: Déclenché lors d'un changement du niveau de risque calculé avec notification / alerte
Ces événements sont transmis au serveur avec un horodatage précis, mais cette fois-ci, avec un identifiant d'installation (
UUID
) aléatoire. -
Token
Afin de pouvoir envoyer des événements applicatifs ou des événements de santé au serveur, un token JWT est nécessaire, dans ce cas c'est une solution technique permettant de s'assurer que des événements ne remontent que depuis l'application officielle, afin de rendre plus difficile l'envoi de statistiques "faussées". Ce token est généré par le webservice ROBERT et est récupéré par l'application suite à la synchronisation. Le token a une durée de vie d'uniquement 3 minutes.
Exemple de données contenues dans le token JWT:
{
"jti": "617aec5c-3750-4bc6-afa8-c053d7b1b948",
"iat": 1628871887,
"exp": 1628872067,
"iss": "robert-server"
}
Envoi des statistiques
Le mécanisme d'envoi des statistiques fonctionne avec trois requêtes différentes:
-
Une requête
POST
sur la route/status
.C'est une requête de synchronisation pour le protocole ROBERT. Dans la réponse, le serveur envoie le token JWT.
-
Une première requête
POST
sur la route/analytics
.Cette requête envoie les statistiques liées à l'identifiant de l'application, avec le token d'authentification JWT.
-
Une deuxième requête
POST
sur la route/analytics
.Cette requête envoie les statistiques non liées à un identifiant à long terme, avec le token d'authentification JWT.
Analyse de risques
Nous avons identifié plusieurs façons de réduire les garanties de sécurité de l'application en utilisant les statistiques envoyées. Le serveur central peut notamment:
- Mettre en correspondance les différentes sources de données qui devraient être indépendantes
- Identifier certains utilisateurs
- Récupérer des informations sur la vie privée des utilisateurs
Mise en correspondance des différentes sources de données
L'application TousAntiCovid génère plusieurs types de données, qui doivent normalement rester cloisonnées:
- des données de traçage Bluetooth: ces données sont liées à un pseudonyme, noté
ID
dans la spécification ROBERT; - les événements applicatifs: ces données sont liées à un identifiant
UUID
généré à l'installation de l'application; - les événements de santé: ces données ne sont liées à aucun identifiant pérenne.
Nous avons identifié plusieurs façons de reconstruire une correspondance entre ces données.
Utilisation du token JWT
L'utilisation du token JWT permet au serveur de facilement relier ces informations, et les différents identifiants de l'utilisateur. En effet le token est obtenu en réponse à une requête POST /status
(synchronisation) qui contient le pseudonyme ROBERT ID
, et il est envoyé lors des deux requêtes POST /analytics
(envoi des analytics). La première requête POST /analytics
contient l'identifiant d'application UUID
, et permet de le mettre en correspondance avec le pseudonyme ROBERT. La deuxième requête POST /analytics
ne contient pas d'identifiant, mais elle utilise le même token JWT, donc le serveur peut la mettre en correspondance avec les deux premières.
Corrélation à partir de l'horodatage des requêtes
L'application utilise un délai aléatoire entre l'envoi des statistiques applicatives et l'envoi des statistiques de santé pour éviter une attaque en corrélant l'heure où ces requêtes sont envoyées. Cependant, les données de traçage Bluetooth peuvent être corrélées aux statistiques applicatives, car l'envoi des statistiques applicatives (AnalyticsManager.sendAnalytics
) se fait juste après la requête de synchronisation du traçage Bluetooth (ROBERT) (remoteServiceRepository.status
): https://gitlab.inria.fr/stopcovid19/stopcovid-android/-/blob/tousanticovid_prod_3.7.1%23330/robert/src/main/java/com/lunabeestudio/robert/RobertManagerImpl.kt#L520
Le serveur peut donc inférer que les deux requêtes viennent d'un même utilisateur si elles sont faites l'une après l'autre (en mesurant quand ces requêtes sont reçues). Cela donne un indice permettant de mettre en correspondance le pseudonyme ROBERT ID
et l'identifiant d'application UUID
. Comme ces requêtes sont répétées toutes les 12 heures avec les mêmes identifiants, le serveur peut rapidement obtenir un haut niveau de confiance dans cette correspondance, en croisant les données de plusieurs requêtes successives.
Même si l'application était modifiée en ajoutant un délai aléatoire entre les requêtes, l'événement e16
dans le journal permettrait encore de les mettre en correspondance. En effet cet événement indique l'horodatage de la requête de synchronisation ROBERT, et il est inclus dans les statistiques applicatives.
Événements simultanés dans les journaux d'événements
L'événement applicatif e2
(modification du niveau de risque calculé) est généré en même temps que l'événement de santé eh2
: https://gitlab.inria.fr/stopcovid19/stopcovid-android/-/blob/tousanticovid_prod_3.7.1%23330/stopcovid/src/main/java/com/lunabeestudio/stopcovid/StopCovid.kt#L376
Ces deux événements auront donc le même horodatage précis à la milliseconde près: le serveur peut donc mettre en correspondance la liste des événements applicatifs et la liste des événements de santé d'un même utilisateur, si ces événements ont été générés.
Identification des utilisateurs par les événements
Certains événements rapportés dans les journaux peuvent facilement être reliés à l'identité de l'utilisateur.
Utilisation du convertisseur de certificats
L'application TousAntiCovid permet de convertir un certificat au format français (2D-DOC) vers le format Européen (DCC). Dans le futur, il est prévu d'étendre cette fonction pour gérer des formats de certificats internationaux. L'utilisation du convertisseur de certificat est forcément une opération nominative puisque le certificat contient nom, prénom et date de naissance de l'utilisateur (ou de ses proches), en plus des données de santé.
TousAntiCovid génère les événements e20
et e21
lors de l'utilisation du convertisseur. L'événement e20
est envoyé avant l'envoi de la requête pour convertir le certificat, et l'événement e21
est envoyé après le retour de la requête. Ces deux événements applicatifs permettent donc de déduire une fenêtre temporelle très courte (généralement moins d'une seconde) durant laquelle le convertisseur a été utilisé. Si le serveur central peut croiser ces données avec les données du serveur qui gère le convertisseur de certificat, il peut donc identifier un utilisateur avec son nom, prénom, et date de naissance et lier un identifiant d'application (UUID
) à une identité réelle.
Partages sur les réseaux sociaux
TousAntiCovid propose d'inviter ses amis à utiliser l'application en partageant un message type:
J'utilise TousAntiCovid pour participer à la lutte collective contre l'épidémie : pour informer et être informé. Installez-la vous aussi : https://bonjour.tousanticovid.gouv.fr
Si l'utilisateur a partagé le message sur les réseaux sociaux, son message et l'heure où il a été envoyé sont publics, on peut par exemple chercher ces messages sur Twitter ou Facebook.
TousAntiCovid génère un événement e4
lorsque cette fonctionnalité de partage est utilisée. Le serveur apprend donc quand un utilisateur l'active et peut comparer les horaires des événements de partage dans les statistiques applicatives et des messages publics postés sur les réseaux sociaux. Quand un horaire correspond, le serveur peut relier un utilisateur d'un réseau social à un identifiant d'application (UUID
).
Utilisation des journaux d'erreurs
En cas d'échec de conversion d'un 2D-DOC en DCC, la totalité de la description de l'erreur de conversion et de son code sont ajoutés au journal d'erreur. Cette description peut contenir des informations assez sensibles telles que la signature complète du 2D-DOC lorsque l'utilisateur tente de convertir un document révoqué sur le serveur de conversion mais pas dans TousAntiCovid. Le code d'erreur permet également dans certains cas de déduire des informations sur la nature des documents que l'utilisateur tente de convertir (certificat de vaccination, test antigénique, …).
Plus généralement, les garanties d'anonymat sur les erreurs de conversion de 2D-DOC sont très faibles car le traitement est réalisé sur un document médical nominatif. Il devient alors très simple pour le serveur de corréler les journaux d'erreurs avec une personne physique en utilisant l'horodatage de l'erreur (à la milliseconde près) ou directement le message de l'erreur selon les informations qu'il contient. Les erreurs renvoyées par le backend de conversion sont également suceptibles d'évoluer avec le temps et d'inclure volontairement ou involontairement d'autres données personnelles ou sensibles ; il est alors imprudent de remonter dans les analytics des informations aussi précises sur l'erreur de conversion sous-jacente.
De plus, la remontée d'erreurs de communication avec le serveur ROBERT permet de corréler un installationUUID
avec un pseudonyme ROBERT dès la première erreur de communication du client, en comparant l'horodatage des événements d'erreur avec l'horodatage dans les journaux d'accès du serveur web ROBERT. Aussi, même sans utiliser l'horodatage, un serveur ROBERT malveillant pourrait volontairement, de temps en temps, retourner des codes d'erreur HTTP spécifiques qui pourraient ensuite être comparés avec ceux apparaissant dans les analytics. Ainsi, la réduction de la précision de l'horodatage des erreurs n'est pas une mesure suffisante pour prévenir les possibilités de corrélation.
Journal d'événements très bavard
De façon générale, la liste des événements qui sont enregistrés dans le journal d'événements est très longue et contient des informations qui touchent à la vie privée. L'application enregistre les clics dans la plupart des menus, et envoie au serveur un journal avec des horodatages précis au millième de seconde. Ce niveau de détail est très différent de ce qui est annoncé dans l'AIPD.
Certains événements particuliers révèlent directement des informations privées:
-
L'événement
e2
(modification du niveau de risque) est ajouté dans le journal quand un utilisateur recoit une alerte de traçage TousAntiCovid.Le serveur reçoit donc une donnée de santé (contact à risque) dans la partie "données applicatives" moins protégée.
-
L'événement
e15
est ajouté dans le journal à chaque synchronisation du protocole Cléa. Cette synchronisation a lieu régulièrement si l'utilisateur a scanné des QR-codes de lieu (si la liste est non-vide). Cependant, quand un utilisateur du traçage par QR-code (Cléa) se déclare positif, la liste des lieux visités est envoyé au serveur sans identifiant de l'utilisateur, puis vidée.Le serveur peut donc inférer qu'un utilisateur a été testé positif si l'événement
e15
cesse d'apparaitre dans le journal. Encore une fois, c'est une donnée de santé, qui est liée à l'identifiant de l'applicationUUID
. -
L'événement
e14
(ajout d'un lieu visité) est ajouté dans le journal quand un utilisateur scanne un QR-code de lieu (Cléa).Si l'envoi de statistiques est activé, le serveur reçoit tous les horaires où l'utilisateur a scanné des QR-codes de lieu (événement
e14
). Cela viole les promesses du protocole Cléa. La spécification dit:no information is uploaded to the server unless a client is tested COVID+
aucune information n'est envoyée au serveur à moins que l'utilisateur ne soit testé positif
Le serveur reçoit seulement l'horaire de scan du QR-code de lieu, sans autre détail, mais cela est suffisant pour apprendre une partie du graphe social en cherchant des corrélations entre les horaires de scan. Si deux utilisateurs vont souvent au restaurant ensemble, il y aura plusieurs paires d'événements
e14
avec des horaires proches. -
L'événement
e13
est ajouté dans le journal quand l'utilisateur ajoute un passe sanitaire dans le wallet.Le serveur reçoit seulement les horaires d'ajout de passes sanitaires, sans autre détail, mais cela permet d'inférer le statut vaccinal. En effet, si un utilisateur ajoute régulièrement des passes dans l'application, il est probablement non-vacciné et fait régulièrement des tests COVID. Cette information ne sera pas toujours exacte (l'utilisateur peut ajouter plusieurs fois le même pass vaccinal), mais c'est un indice fort sur une donnée de santé.
Statistiques manquantes
Dans le cas où un utilisateur n'a jamais activé le traçage bluetooth, l'application n'envoie pas de statistiques. Malgré les statistiques très bavardes, on ne pourra donc pas répondre à une question aussi simple que "quelle proportion des utilisateurs TousAntiCovid ont activé le traçage Bluetooth ?". Les utilisateurs qui se servent de TousAntiCovid uniquement pour stocker leur passe sanitaire n'apparaitront pas dans les statistiques.
Ce problème vient de la façon dont l'envoi des statistiques est securisé, nécessitant un token JWT qui est reçu uniquement à la suite d'une synchronisation de la partie traçage Bluetooth de l'application (ROBERT).
Suppression des données
L'utilisateur a la possibilité, dans l'application, de supprimer les données statistiques le concernant (à travers "Parametres" > "Statistiques et mesure d'audience" > "Supprimer mes données"), mais l'analyse du code publié ne nous permet pas de vérifier que la suppression est pleinement effective.
Dans le schéma ci-dessus, publié sur le dépôt Gitlab, on voit que le message entre dans Apache Kafka:
le serveur reçoit la demande de suppression de l'utilisateur, avec l'identifiant de l'application (UUID
).
Le schéma évoque ensuite Zookeeper et Logstash.
Apache Zookeeper est un outil qui permet de coordonner des systèmes distribués (en l'occurrence le cluster Kafka). Logstash permet de collecter, filtrer et transformer des événements issus de plusieurs sources avant de les envoyer dans un (ou plusieurs) entrepôt(s) de données, ici Elasticsearch. L'événement est donc potentiellement enregistré à deux endroits différents: Kafka et Elasticsearch.
Le code disponible ne nous permet pas de vérifier que les événements sont bien supprimés dans ces deux systèmes, ni comment est faite la suppression des données (suppression des événements eux-même ou anonymisation en supprimant l'identifiant de l'installation UUID
). L'application mentionne aussi une suppression automatique des données au bout de 3 mois, mais là aussi aucune visibilité n'est donnée sur la façon dont cette suppression automatique est réalisée, ni aucune garantie sur sa réalisation.
De plus, un événement applicatif est envoyé lorsque l'utilisateur clique sur le bouton "Supprimer mes données" (e17
). Si les données sont réellement supprimées, alors cet événement n'a pas de sens: suite à la synchronisation, l'envoi des statistiques se fait en premier et, si une demande de suppression est en attente, celle-ci se fait uniquement après cet envoi et vient donc théoriquement supprimer les événements que l'application vient de transmettre au serveur.
Enfin, nous remarquons que lorsqu'un utilisateur perd son identifiant d'installation (UUID
) (ce qui pourrait arriver, par exemple, suite à un bug de l'application, en perdant son téléphone ou encore en désinstallant l'application), il se retrouve dans l'impossibilité de supprimer ses données du serveur.
Information des utilisateurs
Le système de statistiques a été ajouté dans la version 2.5.0 de l'application puis activé au moment de la sortie de la version 3.1.3 le 1er juin 2021, probablement à l'insu de l'écrasante majorité des utilisateurs.
Mise à jour du décret
Ce nouveau traitement dans l'application s'appuie sur le décret n° 2021-157 du 12 février 2021 qui modifie le décret n° 2020-650. En particulier, il a étendu les finalités du traitement de TousAntiCovid (anciennement StopCovid) pour permettre la réalisation d'analyses statistiques « afin […] d'améliorer les performances de l'application ».
La Politique de confidentialité de l'application a aussi été modifiée entre le 20 avril 2021 et le 29 avril 2021 pour prendre en compte la collecte des nouvelles statistiques, en élargissant la finalité de la production de statistiques « à des fins de diagnostics, d’amélioration de performance et de l’expérience utilisateur » alors que la version précédente était restreinte à « améliorer l’efficacité du modèle de santé utilisé par l’application ».
Cependant, ni le décret, ni la polique de confidentialité (ni la version de l'AIPD à laquelle nous avons accès) ne précisent l'ensemble des données collectées et transmises par le système de statistiques. L'article 2 du décret liste toutes les données traitées par l'application, mais rien ne correspond aux journaux d'événements. Certains événements, particulièrement ceux relatifs aux données de santé, peuvent difficilement se justifier par la simple finalité d’amélioration de performance et de l’expérience utilisateur. La collecte et l'envoi des journaux d'événements semble donc contraire au décret.
Consentement
Nous n'avons pas observé de mécanisme dans l'application permettant d'avertir les utilisateurs en cas de modification de la politique de confidentialité. Il semblerait donc que la collecte des statistiques ait été activée sans informer les utilisateurs existants de la nouvelle finalité. Pour les nouveaux utilisateurs, nous constatons que la collecte des statistiques est activée par défaut.
La CNIL s'était prononcée le 17 décembre 2020 (Délibération n° 2020-135 publiée le 14 février) quant à l'extension des finalités prévues dans le décret. Dans cette délibération, la CNIL rappelle notamment que:
Dans l'hypothèse où l'élaboration de telles statistiques nécessiteraient la mise en œuvre d'opérations de lecture ou d'écriture sur le terminal de l'utilisateur, la Commission rappelle que celles-ci pourront être exemptées de consentement sous la réserve que ces opérations soient conformes à l'article 5 des lignes directrices de la Commission relatives aux « cookies et autres traceurs ». A défaut, le consentement devra être recueilli, conformément à l'article 82 de la loi du 6 janvier 1978 modifiée.
L'exemption du recueil de consentement mentionné par la CNIL n'est possible que sous certaines conditions, qui ne sont pas toutes respectées par l'application TousAntiCovid. En particulier:
Dès lors, la Commission considère que peuvent bénéficier de cette exemption au recueil du consentement, les traitements respectant les conditions suivantes :
- […]
- la personne doit être informée préalablement à leur mise en œuvre ;
- […]
- la finalité du dispositif doit être limitée à (i) la mesure d'audience du contenu visualisé afin de permettre l'évaluation des contenus publiés et l'ergonomie du site ou de l'application, (ii) la segmentation de l'audience du site web en cohortes afin d'évaluer l'efficacité des choix éditoriaux, sans que cela ne conduise à cibler une personne unique et (iii) la modification dynamique d'un site de façon globale. Les données à caractère personnel collectées ne doivent pas être recoupées avec d'autres traitements (fichiers clients ou statistiques de fréquentation d'autres sites, par exemple) ni transmises à des tiers. L'utilisation des traceurs doit également être strictement cantonnée à la production de statistiques anonymes. Sa portée doit être limitée à un seul éditeur de site ou d'application mobile et ne doit pas permettre le suivi de la navigation de la personne utilisant différentes applications ou naviguant sur différents sites web ;
- […]
Comme nous l'avons vu, les finalités du traitement excèdent de très loin la simple mesure ou segmentation d'audience, ne sauraient être considérées comme un système de production de « statistiques anonymes », et l'utilisateur n'est pas correctement informé de la mise en œuvre du traitement. Il faudrait donc limiter les finalités du traitement, ou alors demander le consentement explicite de l'utilisateur et adapter le décret en conséquence.
Changement d'architecture
Nous constatons aussi que l'avis de la CNIL du 17 décembre 2020 se base apparemment sur une architecture de collecte de statistiques qui n'est pas la même que celle qui a effectivement été deployée en avril 2021. En effet, il dit:
La Commission relève que ces données, transmises au serveur central au moment de la remontée de l'historique de proximité des contacts à risque de contamination, ne sont pas liées aux identifiants des personnes effectivement contaminées, ce qui apparait une mesure de minimisation protectrice de la vie privée des personnes concernées.
Le Comité de Contrôle et de Liaison COVID-19 (CCL) mentionne aussi cette architecture dans son avis du 15 décembre 2020:
Concernant la dimension confidentielle, quand une personne choisit de se déclarer positive dans TAC, elle autorise la remontée de ses contacts sans jamais faire remonter son identifiant. C’est dans cette remontée que les données statistiques se retrouvent, sans lien donc avec des données nominatives ou pseudonymisées.
Nous avons vu que la version actuellement déployée n'envoie pas les données au moment de la remontée de contacts prévue par le protocole ROBERT, mais à intervales réguliers même si l'utilisateur n'est pas testé positif. En particulier le système actuel serait beaucoup plus bavard que celui sur lequel la CNIL s'est prononcé. Nous remarquons aussi que la remontée de l'historique de proximité nécéssite un code de décaration issu d'un document médical, et n'est donc pas « sans lien donc avec des données nominatives ou pseudonymisées ».
Discussion et contre-mesures
Ces problèmes sont directement liés à des choix de conception de l'application TousAntiCovid, en particulier le choix de mettre dans la même application différents systèmes qui devraient être indépendants: (i) le traçage de contact Bluetooth (ROBERT), (ii) le traçage de contact par QR-codes de lieux (Cléa), (iii) le wallet pour le pass sanitaire, (iv) le convertisseur de certificats. Ces systèmes doivent être indépendants puisque le pass sanitaire est nominatif alors que les systèmes de traçages promettent de protéger la vie privée. En les intégrant dans la même application, des attaques deviennent possibles car ces différentes fonctions partagent une partie de l'état du système, comme les journaux d'événements, les minuteries qui déclenchent les requêtes de status, et les tokens d'autorisation.
Un autre problème est que les statistiques sont beaucoup trop détaillées. Une façon simple de réduire le risque lié à la télémétrie serait de supprimer certains événements. De plus, toute mesure visant à réduire la quantité de données et méta-données présentes lors de l'envoi des journaux d'événements réduirait de facto les risques de perte de confidentialité. Par exemple :
- Les événements sont actuellement envoyés avec une date à la micro-seconde près, alors qu'une précision d'une heure ou d'une journée suffirait probablement pour l'analyse statistique ;
- La route d'envoi des statistiques pourrait être anonyme et ne pas nécessiter l'envoi d'un token d'authentification. En outre, même si un tel token d'authentification s'avérait nécessaire, il pourrait être obtenu auprès du serveur d'analytics plutôt qu'auprès du serveur ROBERT, en prenant soin qu'il ne permette pas de corréler les healthAnalytics et les appAnalytics (notamment par des attaques basées sur le temps) ;
- L'utilisation d'un mixnet permettrait d'éviter les techniques de corrélation et de perte de confidentialité basées sur la connaissance de l'IP du client ;
- Changer régulièrement l'ID d'installation voire y renoncer complètement en implémentant des logiques de comptage côté client mitigerait les possibilités pour le serveur de compromettre la confidentialité de l'ensemble du journal d'un utilisateur lorsque la confidentialité d'un seul événement du journal est compromise ;
- Il n'est probablement pas utile d'inclure tant de méta-données dans les structures
AppInfo
etHealthInfo
; - Les journaux d'erreur pourraient être envoyés séparément des journaux d'événements et sans identifiant d'installation. En outre, lors de la communication avec le serveur ROBERT ou avec le serveur de conversion 2D-DOC, la remontée des erreurs pourrait être abandonnée au profit d'un système de monitoring et de reporting d'erreurs coté serveur.
L'envoi des statistiques d'utilisation de l'application à un serveur central ne devrait pas être systématique pour tous les utilisateurs, mais plutôt opt-in au lieu du opt-out actuel. La possibilité de supprimer ses données est un plus, mais il faudrait donner des explications et des garanties sur le mécanisme et les procédures de suppression qui s'ensuivent.
L'architecture technique des serveurs TousAntiCovid limite aussi le risque en découpant les services sur plusieurs machines indépendentes. Cependant, il est impossible de vérifier que le serveur est bien implémenté comme promis et que ces machines n'échangent pas d'information. Notre analyse suit donc le modèle de sécurité décrit dans la spécification de ROBERT (honest-but-curious), en supposant que l'autorité centrale collecte et centralise le plus d'information possible.
Remerciements
Merci à Florian Maury et Tara Bassirian d'avoir fait une relecture du document.