Hackfest Communication Blog

Nouvelles et opinions de la communauté de sécurité informatique

Analyse d'une vulnérabilité de l'application VaxiCode Verif

31 August 2021

Un faux VaxiCode

  • Rédigé par un collaborateur anonyme

Comprendre les SMART Health Cards

La SMART Health Card (SHC), contenant les informations enregistrées dans votre code QR, est basée sur une technologie éprouvée connue sous le nom de JSON Web Signature (explicatif, spécification JWS).

Les JWS permettent, entre autres, la signature cryptographique de données arbitraires (le payload), ainsi que leur vérification à l’aide d’informations (les entêtes) contenues à même ces données, soit la clé publique et la méthode de signature.

Cette même technologie est utilisée pour bâtir d’autres technologies telles que JSON Web Token, la suite de spécifications Open ID, et autres, qui sont très fréquemment utilisés pour enregistrer des données hors d’un environnement contrôlé tout en assurant la validité vérifiable de celles-ci. Par exemple, si vous utilisez fréquemment les services Google, cette même technologie est utilisée pour vous connecter à ceux-ci de manière sécuritaire.

Le concept de signature implique une clé privée et une clé publique. L’entité (le gouvernement du Québec) qui publie les données (le code QR représentant le SHC) utilise la clé privée pour signer celles-ci, et les applications qui les consomment utilisent la clé publique (l’app VaxiCode Verif) pour valider que ces données n’ont pas été modifiées par une personne malveillante. Sans entrer dans les détails, les données signées sont ensuite considérées comme sûres et vérifiables. Pour plus d’informations, nous vous invitons à consulter cet article sur les signatures.

Maintenant que nous savons que les données du SHC sont inviolables, que contient votre code QR? Celui-ci contient quelques informations, appelées claims.

Un premier claim, iss ou issuer, identifie l’entité qui publie ces données. Un autre, iat ou issued at indique la date où elles ont été publiées. Enfin, un claim nommé vc ou verifiable credentials contient les informations cruciales du SHC.

Sont présents dans ces dernières le type de données que le SHC contient (données d’immunisation, contexte COVID-19 et autres), et une liste d’entrées.

Une en particulier décrit le patient (vous) dont fait l’objet le SHC. Dans celle-ci, se trouvent uniquement votre prénom, nom de famille ainsi que votre date de naissance.

Ensuite, pour chaque dose de vaccin reçue, vous trouverez aussi les informations décrivant quel vaccin a été reçu, à quelle date et le nom de l’endroit où l’injection a été réalisée.

La vulnérabilité

Revenons maintenant à la problématique principale, soit la vulnérabilité contenue dans les version 1.0.1 et antérieures de l’app VaxiCode Verif.

Celle-ci permettrait à l’application de valider des codes qui n’ont pas été émis par le gouvernement du Québec. Par là, on entend qu’une personne serait en mesure d’émettre et signer elle-même un SHC, par ce fait réussissant à déjouer la vérification faite par l’application que les données qui y sont incluses sont bel et bien véridiques (signature) et cautionnées par la seule autorité ayant actuellement la capacité d’émettre les SHC (claim iss).

Cette vulnérabilité a été rendue publique en premier le vendredi 27 août 2021 dans un article de Radio-Canada.

Avenues possibles de vulnérabilité

Avant de valider la vulnérabilité de l’application de vérification, parcourons plusieurs problèmes communs dans l’implantation de validations de JWS et technologies similaires qui pourraient permettre un tel résultat.

La vulnérabilité ayant été trouvée moins de 24h après la sortie de l’application, il est peu probable que les failles soient le résultat d’opérations très compliquées. Commençons par ces quelques vérifications de base:

  1. Les clés publiques sont bel et bien utilisées pour valider le contenu du JWS?
  2. La validation du claim iss se fait correctement?
  3. Les JWK externes sont-ils téléchargés et utilisés?
  4. Les clés sont-elles bien utilisées?
  5. Serait-ce possible que des modes de signature non sécuritaires soient permis (spécifiquement, alg: "none")?

Outils utilisés

Les outils communs suivants ont été utilisés pour la majorité des tests:

  • http-server pour servir des fichiers pendant les tests.
  • ngrok pour rendre le serveur disponible publiquement.
  • @pathcheck/shc-sdk pour facilement générer des SHC, JWKS et autres. Celle-ci utilise le package courant node-jose.
  • Smart Health Card Scanner pour inspecter les SHC facilement.
  • Une application de scan QR pour lire le contenu des codes QR.

Pour valider alg: "none" ceux-ci ont été ajoutés à la liste:

  • node-jwa pour générer des JWS avec ce type d’algorithme.
  • pako pour compresser le payload du JWS.

Vérifications

Utilisation de la clé publique du gouvernement et utilisation du claim iss

Pour commencer, un QR existant a été scanné pour obtenir la chaine de caractères composant le SHC. Ce dernier a été ouvert dans le Smart Health Card Scanner pour rapidement visualiser son contenu.

Le contenu de celui-ci a été copié dans un script permettant de générer un nouveau SHC à l’aide de SHC-SDK, mais signé avec un JWK différent que celui de l’application. Le payload a été laissé identique.

Par la même occasion, on laisse le claim iss à l’identique pour valider que cela ne permet pas d’ignorer la validation de la signature.

Résultat: VaxiCode Verif indique un message d’erreur: Ce code QR n’est pas une preuve de vaccination valide. On assume que la signature a bien été validée et que le claim iss ne permet pas de contourner celle-ci.

Ce code QR n'est pas une preuve de vaccination valide

Les JWK externes

JWK est un format permettant l’échange de clés cryptographiques qui est utilisé lors de la validation des signatures des SHC émis par le gouvernement. On parle de JWKS quand il s’agit d’un ensemble de clés (JSON Web Key Set).

Nous tentons d’importer un JWKS externe au chemin .well-known/jwks.json. Un serveur HTTP local très simple est mis en place derrière un tunnel pour le rendre disponible publiquement avec le protocole HTTPS. Le claim iss est changé pour le domaine du tunnel (pour référence, appelons le Serveur.Local). Un JWKS est lui aussi généré, puis placé dans le dossier .well-known, puis le SHC est généré est scanné. Le JWKS est donc accessible à l’adresse https://Serveur.Local/.well-known/jwks.json.

Résultat: Le proxy indique avoir en effet reçu un appel à GET /.well-known/jwks.json. Au moment du scan, VaxiCode Verif indique une erreur: Certifié par une autorité inconnue. Serveur.Local. On assume que les JWK ont bien été importés. Cela est entièrement normal jusque là.

Certifié par une autorité inconnue. Serveur.Local

Usage des clés publiques

Nous tentons maintenant de voir si le JWK qui a été importé est uniquement utilisable par le issuer de celui-ci. Nous remettons le claim iss à sa valeur initiale (https://covid19.quebec.ca/PreuveVaccinaleApi/issuer) et générons un nouveau SHC, puis le scannons.

Résultat: Le SHC est accepté comme véridique. Nous avons reproduit la vulnérabilité. Nous déduisons que le JWK qui a été importé à la dernière étape n’a pas été correctement marqué comme étant utilisable uniquement par le issuer Serveur.Local pour valider les signatures, et que le issuer https://covid19.quebec.ca/PreuveVaccinaleApi/issuer est maintenant capable de valider les signatures avec les clés de Serveur.Local, ce qui ne devrait jamais arriver.

SMART Health Card autorisé

Signatures non sécuritaires

Un JWS conforme semblable au format SHC a aussi été créé et scanné, mais avec l’entête suivant:

{
  "alg": "none",
  "zip": "DEF"
}

alg: "none" indique au vérificateur de signature qu’il n’y a pas de signature à vérifier.

Résultat: L’app VaxiCode Verif est simplement incapable de reconnaitre un code QR de ce type. Pas de vulnérabilité ici.

Analyse

Le problème causant la vulnérabilité est mentionné dans la spécification des SHC. C’est la responsabilité du groupe développant une application faisant usage de la norme SHC d’y porter attention. Le problème est décrit directement:

  1. dans la spécification SHC, sections Signing Health Cards et Determining keys associated with an issuer ainsi que
  2. dans la spécification JWS, section Key Origin Authentication, de laquelle cette première hérite.

“10.3. Key Origin Authentication: The key management technique employed to obtain public keys must authenticate the origin of the key; otherwise, it is unknown what party signed the message.”

Extrait de la spécification JWS

En termes plus clair, il faut s’assurer que la signature ne soit vérifiée seulement qu’avec les clés provenant de l’issuer, mais l’implantation dans l’application VaxiCode Verif ne le faisait pas pour les versions <=1.0.1.

Les codes QR sont-ils compromis?

Non. Tel que mentionné, les code QR qui contiennent les informations SHC sont conformes à la spécification et sont entièrement sécuritaires.

Ici, la première partie du problème réside sur le fait que les clés utilisées pour vérifier les codes ne sont pas uniquement associées à leurs émetteurs respectifs. Il s’agit d’une omission regrettable, cependant (et heureusement), celle-ci est facile à régler.

De plus, l’application ne devrait valider que les émetteurs de confiance, ce qui semble être le cas, mais qui reste à vérifier suite à la correction.

Validation de la correction

Le dimanche 29 août 2021, une nouvelle version de VaxiCode Verif, 1.0.2, a été publiée sur le Apple App Store. Les changements sont décrits ainsi:

  • Amélioration du vérificateur de preuves
  • Améliorations pour les écrans de plus petite taille
  • Améliorations d’accessibilité

Nous avons utilisé la même marche à suivre que celle décrite plus haut pour tenter de valider le correctif.

Résultat: La vulnérabilité a bien été corrigéée, et nous ne sommes plus capables de l’exploiter.

Sans avoir accès au code de l’application, il est difficile de décrire exactement les correctifs effectués. Cependant, nous sommes tout de même en mesure de faire quelques observations. La plus importante concerne le fait que l’application ne télécharge plus les JWKS externes au chemin /.well-known/jwks.json de l’issuer, elle n’est alors plus en mesure de faire ni l’importation, ni la validation des signatures générées avec des clés autres que celle du gouvernement. De plus, le message d’erreur affiché dans ce cas n’est plus Certifié par une autorité inconnue. Serveur.Local, mais bien Ce code QR n’est pas une preuve de vaccination valide.

Ce code QR n'est pas une preuve de vaccination valide