Files
cv-maker/docs/conception/06-securite-rgpd.md
T

5.7 KiB

06 — Sécurité et conformité RGPD

1. Analyse de risque (résumé)

Menace Vecteur Niveau (v1) Contre-mesure
XSS — injection de HTML/JS saisi par l'utilisateur champ Markdown rendu via dangerouslySetInnerHTML élevé si non traité DOMPurify.sanitize() systématique sur le HTML produit par marked
Vol de données exfiltration réseau nul aucune donnée quitte le navigateur (pas d'API, pas d'appel distant)
Corruption de la sauvegarde JSON invalide en localStorage faible parsing try/catch + validation de forme + valeur par défaut
Quota localStorage dépassé très gros CV faible erreur catchée + console.warn (enregistrement silencieux)
Données lues par un tiers sur le poste accès local au navigateur hors périmètre relatives au poste utilisateur (aucune garantie applicative possible)

Rappel : le seul point d'entrée présentant un risque d'exécution est le rendu HTML. Mitigé par la règle « aucun HTML brut n'est injecté, uniquement le résultat de markdownToHtml (marked → DOMPurify) ».

2. Chaîne de rendu sécurisée (obligatoire)

Markdown brut (textarea)
      │  marked.parse (GFM, breaks)
      ▼
HTML intermédiaire non sûr
      │  DOMPurify.sanitize(html, { USE_PROFILES: { html: true } })
      ▼
HTML assaini
      │  dangerouslySetInnerHTML={{ __html: sanitizedHtml }}
      ▼
DOM

Règles d'implémentation

  1. Toute injection dans le DOM passe exclusivement par lib/markdown.ts → markdownToHtml.
  2. Ne jamais injecter la saisie brute (une textarea n'est pas un <script> : le texte est du texte ; le risque n'apparaît que lors du rendu HTML).
  3. Ne pas surcharger la config DOMPurify par zone ; une configuration unique module 06- est utilisée partout.
  4. marked options stables : gfm: true, breaks: true. Ne pas activer d'extension/plugin non maîtrisé.
  5. Le rendu est déterministe (pas de rendu serveur du Markdown utilisateur pour les zones interactives — le client est le seul excécutant).
  6. dompurify est importé seulement dans les composants client (prérequis window), jamais dans un composant serveur/réseau.

Ce que DOMPurify bloque (défauts)

  • balises <script>, <iframe>, <object>, <embed>, <svg> non sûres ;
  • gestionnaires d'événements inline (onclick=, onerror=) ;
  • URLs javascript: dans href/src ;
  • tout futur composant exotique inconnu.

3. Données personnelles : état de l'analyse

Les zones 1 à 6 du CV contiennent des données à caractère personnel (nom, e-mail, téléphone, histoire professionnelle).

Propriété État
Stockage localStorage du navigateur, sur le poste seulement
Transmission aucune (pas d'envoi réseau, pas de cookies, pas de tracker, pas d'analytics)
Durée de conservation jusqu'à effacement des données du navigateur, ou « Réinitialiser le CV » dans l'application
Accès celui qui possède le poste/navigateur
Base légale (contrôle qualité RGPD) l'utilisateur est le seul responsable et destinataire ; aucune RGDP externe ne traite ces données

Conclusion : l'application n'effectue aucun traitement débordant l'usage personnel de l'utilisateur. La page /mentions-legales doit le formuler clairement et fournir les droits usuels (accès, rectification, suppression — effectuables directement dans l'app/browser).

4. Contenu de la page /mentions-legales (modèle de rédaction)

Sections à inclure (v1 : sans paragraphe contact) :

  1. Titre — « Mentions légales ».
  2. Éditeur / responsable de traitement : l'utilisateur lui-même (pas d'entité tierce).
  3. Données traitées : les contenus saisis (état civil, contacts, parcours…).
  4. Finalité : production d'un CV local ; aucune transmission.
  5. Stockage : localStorage du navigateur (clé cv-maker:v1), jamais envoyé à un serveur.
  6. Durée de conservation : tant que les données du navigateur existent ; possibilité de suppression immédiate.
  7. Droits de la personne concernée : libre disposition des données — modification/suppression dans l'éditeur ; effacement possible via les outils du navigateur (suggestion d'actions concrètes) ou le bouton « Réinitialiser ».
  8. Sécurité : rendu assaini (aucune exécution de contenu saisi), aucune dépendance réseau.
  9. Contact : section retirée en v1 (cf. demande utilisateur).
  10. Date de mise à jour de la page.

5. Sécurité applicative transversale

  • PWA/service worker : le SW ne précache que des routes statiques internes ; aucun champ utilisateur n'y est inscrit (les données restent dans localStorage, hors périmètre du cache de pages).
  • Dépendances : audit régulier pnpm audit ; mise à jour de marked/dompurify (les deux librairies de sécurité critiques).
  • Headers de réponse (side) : valeurs par défaut convenables pour Next.js de production ; pas d'en-tête supplémentaire requis côté local (pas de cookies).
  • Content-Security-Policy (recommandation) : à documenter comme évolution — les pages statiques ne chargent aucun script tiers, une CSP stricte est triviale à ajouter hors v1 si hébergé.

6. Checklist sécurité avant livraison

  • Toute zone rendue passe par markdownToHtml (relire chaque dangerouslySetInnerHTML).
  • Aucun appel réseau dans le code applicatif (grep fetch(, axios, XMLHttpRequest dans app/ et components/).
  • pnpm audit sans vulnérabilité de haut niveau.
  • Test manuel d'injection : saisir <img src=x onerror=alert(1)> et <script>alert(1)</script> dans chaque zone → aucune exécution.
  • Page /mentions-legales présente et linker depuis le footer (masqué à l'impression).