medicus.global · 2026-05-05
"Toutes les informations, je les ai saisies moi-même, et je consens à
ce que les secours et les médecins puissent les lire — pour leur
donner la meilleure connaissance préalable possible de ma situation
personnelle, particulièrement dans une urgence. Mon amour pour la
vie est plus grand que les règles du pays sur la protection des
données."
C'est la décision adulte, volontaire qui se trouve derrière chaque profil My Medicus créé. Notre tâche est d'honorer le choix de la patiente : conserver les données en sécurité, ne les montrer qu'à celui qui a le bon PIN, laisser la patiente voir chaque scan, et permettre à la patiente de révoquer la carte à la seconde où elle est perdue. Le reste de ce document explique comment.
"Quelle est votre sécurité concernant My Medicus ?"
Dans une urgence, le plus grand souhait de la patiente est de guérir. C'est elle que nous servons. La sécurité est le moyen, pas la fin.
Trois principes prévalent sur tout :
Nous avons documenté 19 scénarios d'attaque différents contre My Medicus et exécuté chacun contre le système de production. Le résultat est décrit ci-dessous — sans langage marketing, sans "standard de l'industrie", sans "best practice". Juste ce qui a été testé concrètement.
19 scénarios d'attaque contre deux comptes dans la base de données live — un compte démo et un nouvel utilisateur réel. Outils : requêtes HTTP directes, exécution parallèle, introspection SQL de la base de données de production, parsing des réponses.
Résultat : 14 attaques ont rencontré des défenses qui ont tenu. 5 vulnérabilités ont été trouvées et fermées le jour même.
| Attaque | Pourquoi l'attaque a échoué |
|---|---|
| Vol de toute la base de données | Allergies, médicaments, identifiants nationaux, passeport, EHIC et numéros d'assurance sont chiffrés avec AES-256-GCM. La clé vit dans un magasin de secrets séparé, jamais dans la base de données. Si vous volez le fichier DB, vous obtenez du texte illisible |
| Force brute sur PIN à 6 chiffres | Délais progressifs s'activent au 5e essai erroné : 5 sec → 30 sec → 60 sec entre chaque |
| Injection SQL sur formulaire de connexion | Toutes les requêtes de base de données utilisent des requêtes paramétrées — cinq payloads d'injection différents ont été rejetés |
| Appels API directs sans connexion | Tous les endpoints protégés renvoient HTTP 401 |
| Devinette de tokens | Les tokens sont 32 caractères hex dérivés via SHA-256. Espace de recherche : 16^32. 50 essais aléatoires → 0 succès |
| Path-traversal vers backups ou config | /_db_backups/, /.env, /.git, /medicus.db, /wp-config.php renvoient tous 404 |
| Énumération d'emails via "mot de passe oublié" | Réponse générique cohérente, que l'email existe ou non — pas de fuite d'info |
| XSS dans les champs publics | Le serveur rejette les entrées malformées, pas de réflexion HTML/JS |
| Vol physique de portefeuille sans PIN de la carte | Le verrou PIN arrête tous les essais incorrects |
| 10 essais parallèles de force brute | Le rate-limit s'applique par token, pas par requête |
| Suppression du journal d'audit via endpoint DELETE | Aucun endpoint DELETE exposé |
Devinette d'admin-token (admin, 1234, letmein) |
Tous renvoient 401 |
| Tentative de faire fuir des secrets au serveur via payloads d'erreur | Ni la clé de chiffrement ni les secrets Stripe n'apparaissent dans la sortie d'erreur |
| Abus cross-origin depuis un autre site | Le navigateur bloque selon la same-origin policy |
| # | Quoi | Sévérité | Ce qui a été fait |
|---|---|---|---|
| F1 | La connexion répondait 200 ms plus lentement quand l'email était enregistré que quand il ne l'était pas. Un attaquant pouvait déterminer si un compte existe | 🔴 Critique | La connexion exécute maintenant la vérification Argon2id toujours (aussi contre des emails inconnus, avec un hash dummy). Temps de réponse constant. Message d'erreur générique |
| F2 | Pas d'en-têtes de sécurité (HSTS, CSP, X-Frame, X-Content-Type, Referrer-Policy, Permissions-Policy) | 🔴 Critique | Les 6 en-têtes sont maintenant ajoutés sur toutes les réponses via middleware. CSP verrouille script/img/style/frame à des sources whitelistées |
| F3 | Une carte volée a QR + PIN imprimés directement dessus. Le voleur a accès jusqu'à révocation par le propriétaire | 🟠 Élevé | (1) Patient voit chaque scan dans son tableau de bord ("Mon journal" — préfixe IP, pays, heure). (2) Propriétaire peut révoquer la carte en un clic → toutes les cartes imprimées meurent instantanément + nouveau PIN généré |
| F4 | /admin renvoyait du SPA-HTML à tous, ce qui révélait l'existence du panel admin |
🟡 Faible | Renvoie maintenant le même 404 que les routes inexistantes pour les utilisateurs non authentifiés |
| F5 | Mot-de-passe-oublié pouvait être abusé pour inonder la boîte mail d'une cible (1 000 mails/heure) — et nuire à notre réputation d'expéditeur | 🟠 Élevé | Si l'utilisateur a un token reset valide (max 2 heures), il est réutilisé au lieu d'envoyer un nouveau mail. Plus rate-limit par email de 2/min |
| Choix | Justification |
|---|---|
| Pas d'authentification nationale dans la vue secouriste | Le patient est inconscient sur le terrain de golf. Le secouriste n'a pas d'authentification nationale, et même s'il l'avait, nous n'avons pas 90 secondes pour le connecter. PIN-sur-carte est la réponse pratique |
| Pas "zero-knowledge" | Le serveur PEUT déchiffrer les champs — c'est la condition pour que le secouriste puisse voir les données. Nous n'appelons pas "zero-knowledge" ce qui ne l'est pas |
| Pas d'import automatique de données | Chaque champ est choisi par l'utilisateur. Pas d'auto-import depuis d'autres plateformes de santé |
Si un secouriste scanne légitimement la carte avec le bon PIN, il peut photographier l'écran. Nous ne pouvons pas empêcher cela — c'est le prix pour que les données puissent du tout être affichées dans une urgence. Défense :
C'est le même modèle de sécurité qu'un bracelet d'identification médicale physique chez les diabétiques : les données sont visibles aux secours, nous acceptons qu'un pickpocket puisse aussi les voir. La différence est que notre modèle donne au patient le contrôle sur qui voit quoi et quand — pas seulement la visibilité.
Questions ? Écrire à peter@medicus.global