Nouvelles et opinions de la communauté de sécurité informatique
31 August 2021
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.
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.
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:
iss
se fait correctement?alg: "none"
)?Les outils communs suivants ont été utilisés pour la majorité des tests:
Pour valider alg: "none"
ceux-ci ont été ajoutés à la liste:
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.
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à.
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.
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.
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:
“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.
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.
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.