Pour les équipes sécurité et les relecteurs d’applications

La sécurité chez Peel

En bref : le contenu des tableaux est chiffré dans le navigateur avec une clé qui vit dans le fragment du lien, si bien que nos serveurs stockent et relaient du texte chiffré qu’ils ne peuvent pas lire. Voici exactement comment, et où sont les limites.

Résumé

  • Le texte des cartes, les noms, les titres de tableaux, les votes et les stickers sont chiffrés en AES-256-GCM avec une clé de tableau générée dans le navigateur. La clé voyage dans le fragment de l’URL (#k=) et n’est jamais envoyée à un serveur.
  • Les actions du facilitateur, l’en-tête du tableau et les snapshots sont signés avec la clé Ed25519 du facilitateur. L’identifiant du tableau est dérivé de cette clé, ce qui permet aux clients de détecter une substitution de clé.
  • Les cartes cachées sont scellées pour le facilitateur (sealed box X25519) jusqu’à la révélation, et liées par des engagements salés pour que le texte révélé ne puisse pas être échangé.
  • Anonyme par défaut : les opérations ne portent aucun identifiant d’auteur ; les votes et réactions utilisent un identifiant aléatoire propre à chaque tableau.
  • Les participants ne s’authentifient jamais. Pas de SDK d’analytics, pas de pub, pas de scripts tiers, à part Paddle.js sur la page de paiement.
  • Uniquement Cloudflare. Les tableaux non revendiqués sont supprimés 60 jours après la dernière visite.

Comment circulent les données

Le fragment d’une URL (tout ce qui suit le #) est géré par le navigateur et ne fait pas partie de la requête HTTP. C’est là que Peel place la clé du tableau.

Flux de données : la clé est lue localement depuis le lien ; seuls le texte chiffré et des métadonnées minimales passent sur le réseau.

Modèle de menace

Nous concevons Peel pour qu’un serveur entièrement compromis ou curieux, nous compris, apprenne le moins possible de ce que dit une équipe.

Ce que nous protégeons

  • Le texte des cartes, le choix des GIF et, en mode nominatif, le nom de l’auteur.
  • Les noms et avatars des participants, le nom du tableau et les titres de modèles personnalisés.
  • Qui a voté ou réagi sur quoi, et qui a écrit quelle carte.
  • L’intégrité de la rétro : étapes, révélations et décisions du facilitateur ne peuvent pas être falsifiées.

Les adversaires envisagés

  • Nos propres serveurs, un initié malveillant, ou quelqu’un qui pénètre notre stockage : ils obtiennent du texte chiffré et des métadonnées.
  • Un attaquant sur le réseau : TLS partout ; la clé ne transite jamais sur le réseau.
  • Un serveur qui substitue les clés : l’identifiant du tableau est dérivé de la clé publique du facilitateur, et les clients vérifient l’en-tête signé.
  • Un participant qui veut jeter un œil ou falsifier : les cartes cachées sont scellées pour le facilitateur ; les opérations du facilitateur exigent sa signature ; modifier une carte exige la clé de la carte.
  • Un facilitateur qui republie pour un auteur hors ligne : les engagements l’empêchent de modifier le texte.

Hors périmètre, en toute franchise

  • Quiconque possède le lien participant peut lire le tableau. Le lien est le contrôle d’accès. Il se partage avec le même soin que le tableau lui-même.
  • Un appareil compromis, une extension de navigateur malveillante, ou quelqu’un qui regarde par-dessus l’épaule.
  • L’analyse de trafic : le serveur voit les horaires, les tailles et les compteurs (voir la cartographie des données).
  • Le déni de service par le serveur : il peut supprimer ou retarder des messages, mais pas les lire ni les falsifier.

Cryptographie

Toutes les primitives viennent de l’API WebCrypto du navigateur. Pas de cryptographie maison, pas de bibliothèques crypto tierces.

CléAlgorithmeUtilisation
K_boardAES-256-GCM, IV aléatoire de 96 bitsChiffre chaque opération, chaque snapshot et chaque mise à jour de présence. Les données additionnelles lient l’identifiant du tableau, le type et l’identifiant de l’opération, si bien qu’un texte chiffré ne peut pas être rejoué dans un autre tableau ou un autre emplacement. Vit uniquement dans le fragment du lien #k=.
K_ownerEd25519L’autorité du facilitateur. Signe les opérations du facilitateur (étape, minuteur, projecteur, modèle, réglages, ouverture des votes, masquage d’une carte), l’en-tête du tableau et les snapshots. Un compteur strictement croissant bloque le rejeu. Uniquement dans le lien facilitateur (&o=).
Identifiant du tableauSHA-256, 80 premiers bits, base32Dérivé de la clé publique du facilitateur : l’identifiant prouve à lui seul quelle clé possède le tableau. Les clients rejettent un en-tête dont la clé ne correspond pas à l’empreinte de l’identifiant.
K_facSealed box X25519 : X25519 éphémère + HKDF-SHA256 + AES-256-GCMLes cartes cachées sont scellées avec la clé publique du facilitateur pendant l’écriture. Seul le lien facilitateur (&f=) peut les ouvrir.
Clés de carteEd25519, une clé par carteDétenue uniquement par l’auteur. Les modifications et la révélation sont signées avec : l’authenticité sans l’identité.
EngagementsHMAC-SHA256 avec un sel aléatoire de 128 bitsUne carte cachée publie un engagement sur son contenu. À la révélation, le contenu et le sel sont publiés et chaque client les vérifie : personne ne peut échanger le texte.
PrésenceAES-256-GCM avec K_boardLes noms, avatars et indicateurs de saisie sont chiffrés comme tout le reste.
Trousseau de clésHKDF-SHA256 à partir du PRF de la clé d’accès ou du code de récupération, AES-256-GCMLes facilitateurs connectés peuvent synchroniser leurs clés de tableau entre appareils. Le trousseau est chiffré sur l’appareil ; le serveur ne stocke que du texte chiffré et des clés enveloppées.

Les messages signés sont séparés par domaine (par exemple peel/sig/v1, peel/header/v1, peel/snap/v1) pour qu’une signature produite pour un usage ne puisse pas être réutilisée pour un autre.

Les cartes cachées et la révélation

  1. Pendant l’écriture, le navigateur de l’auteur scelle la carte avec la clé X25519 du facilitateur et publie un engagement salé. Le texte en clair reste sur l’appareil de l’auteur.
  2. Les autres participants voient une carte cachée : ils ne peuvent pas la déchiffrer, et le serveur non plus.
  3. Le navigateur du facilitateur peut ouvrir les cartes scellées (l’aperçu « 👁 toi seul »).
  4. À la révélation, chaque auteur republie sa carte chiffrée avec K_board, signée avec la clé de la carte, accompagnée du sel.
  5. Si un auteur est hors ligne, le facilitateur republie à sa place. Chaque client vérifie l’engagement : le texte doit correspondre exactement à ce que l’auteur a écrit.

Parce que le facilitateur peut techniquement prévisualiser, chaque tableau affiche à tout le monde la mention « le facilitateur peut prévisualiser » tant que des cartes sont cachées. Ce n’est pas un réglage qu’on peut masquer.

Anonymat

  • Les opérations ne portent aucun identifiant d’auteur. Le serveur ne peut pas relier une carte à une personne, et par défaut le facilitateur non plus.
  • Les votes et réactions sont associés à un identifiant aléatoire propre au tableau, qui n’est lié à aucun nom.
  • Les indicateurs de saisie montrent que quelqu’un écrit, jamais ce qu’il écrit.
  • Le mode nominatif est un réglage explicite du tableau ; le nom de l’auteur voyage alors à l’intérieur de la carte chiffrée.
  • Les participants ne se connectent jamais : il n’y a donc aucun compte à recouper.

Cartographie des données

Tout ce que nous conservons, où cela se trouve, qui peut le lire et combien de temps cela reste.

DonnéesOùLisible parConservation
Cartes, votes, réactions, stickers, actions, nom du tableau, titres de modèles personnalisésStockage Durable Object, sous forme chiffréeLes personnes qui ont le lien du tableauJusqu’à la suppression du tableau
Enveloppe d’opération : type, séquence et heure côté serveur, taille, compteur du facilitateurStockage Durable ObjectPeelJusqu’à la suppression du tableau
Noms et avatars des participants, saisie en coursRelayés sous forme chiffrée ; gardés en mémoire pendant la connexionLes personnes qui ont le lien du tableauPendant la connexion
Statut du tableau : étape, nombre de participants et de cartes, identifiant du modèle du catalogue, indicateur de verrouillage, dates de création et d’expirationDurable Object, D1 ; messages Slack/Teams si installéPeel ; votre canal Slack/TeamsDurée de vie du tableau
Compte facilitateur : identifiant du fournisseur, nom, e-mail s’il est partagé, fournisseurs liés, date de création, sessionD1PeelJusqu’à la suppression du compte
Trousseau de clés et clés enveloppéesD1, sous forme chiffréeUniquement le titulaire du compte (clé d’accès ou code de récupération)Jusqu’à la suppression du compte
Offre, statut de l’abonnement, identifiants client et abonnement PaddleD1 ; PaddlePeel, PaddleSelon les obligations fiscales
Identifiants d’espace de travail, de canal et de message Slack/Teams ; jeton du bot (chiffré en AES-GCM)D1PeelJusqu’à la désinstallation
Adresse IPEdge Cloudflare, de façon transitoire (acheminement, limitation de débit)Cloudflare, le limiteur de débit de PeelNon stockée dans nos bases de données
Compteurs quotidiens (tableaux créés, étapes atteintes)D1PeelAgrégés uniquement, sans identifiant

Ce que notre serveur peut faire, et ce qu’il ne peut pas

Il peut

  • Voir les types d’opérations, les tailles, les horaires, l’étape, le nombre de participants et de cartes, l’identifiant du modèle du catalogue et l’indicateur de verrouillage.
  • Supprimer, retarder ou refuser de livrer des opérations (déni de service).
  • Voir les adresses IP en bordure de réseau.
  • Compter les tableaux et les étapes atteintes, de façon agrégée.
  • Supprimer un tableau (expiration, signalements d’abus).

Il ne peut pas

  • Lire le texte des cartes, les noms, les titres de tableaux, les titres de modèles personnalisés, les votes ou les stickers.
  • Lire les cartes cachées avant la révélation (ni même après).
  • Falsifier les actions du facilitateur : elles exigent sa signature.
  • Substituer ses propres clés : l’identifiant du tableau le trahirait.
  • Modifier le texte révélé d’une carte : les engagements et les signatures de carte le trahiraient.
  • Savoir qui a écrit quelle carte.

Comme pour toute application web, il faut faire confiance au code que nous servons. Nous gardons cette surface réduite : une Content Security Policy stricte, script-src limité à notre propre origine, aucun script tiers, et le protocole est ouvert à l’examen sur demande.

Slack et Microsoft Teams

  • Les messages transportent le lien du tableau et des métadonnées (titre, étape, compteurs). Le texte des cartes n’est envoyé que lorsque le facilitateur publie un résumé et le confirme.
  • La carte « Rejoindre » contient le lien participant, qui inclut la clé. Quiconque peut lire ce canal peut rejoindre, comme si le lien y avait été collé.
  • Les aperçus de liens n’affichent que l’étape et les compteurs, jamais le contenu.
  • Scopes Slack : commands, chat:write, links:read, links:write ; users:read uniquement quand une équipe active les mentions.
  • Les jetons de bot sont chiffrés au repos (AES-GCM, clé conservée comme secret du Worker). Les signatures des requêtes Slack et les jetons Bot Framework sont vérifiés à chaque requête.
  • Désinstaller l’app arrête toute publication et supprime ses jetons.

Web et infrastructure

  • Uniquement Cloudflare : Pages, Workers, Durable Objects, D1, R2 et KV sur le compte de 1801 Labs. Aucun autre serveur.
  • TLS partout, HSTS et une Content Security Policy stricte.
  • Pas de SDK d’analytics, pas de pub, pas de scripts tiers. Seule exception : Paddle.js, chargé uniquement sur la page de paiement.
  • Un seul cookie, uniquement pour les facilitateurs connectés : peel_session, httpOnly, Secure, SameSite=Lax.
  • La recherche de GIF et les médias passent par notre API, si bien que les adresses IP des participants n’atteignent jamais GIPHY.
  • Polices et ressources auto-hébergées. Pas de polices sur CDN, pas de pixels de suivi.
  • Limitation de débit par IP et par tableau ; signalements d’abus et verrouillage par le facilitateur.

Comptes et conservation

  • Les participants ne s’authentifient jamais. Les facilitateurs se connectent avec Google (ou Entra ID via Teams), uniquement pour garder leurs tableaux ou utiliser les fonctionnalités payantes.
  • Un compte stocke un identifiant, le nom et l’e-mail fournis par le fournisseur, et un trousseau de clés chiffré, déverrouillé par une clé d’accès (WebAuthn PRF) ou un code de récupération. Se connecter donne la propriété, pas l’accès au contenu.
  • Revendiquer un tableau prouve la propriété par une signature du facilitateur. Les clés de tableau ne sont jamais envoyées.
  • Les tableaux sans compte sont supprimés 60 jours après la dernière visite ; chaque visite remet le compteur à zéro. Des alarmes Durable Object suppriment le stockage.
  • Supprimer son compte supprime les sessions, le trousseau de clés et la bibliothèque, et redonne aux tableaux leur expiration à 60 jours.

Divulgation responsable

Vous avez trouvé quelque chose ? Prévenez-nous d’abord et nous travaillerons avec vous. Nous accusons réception des signalements sous trois jours ouvrés.

[email protected]

  • Merci de nous laisser un délai raisonnable (nous visons 90 jours) pour corriger avant toute divulgation.
  • Testez avec vos propres tableaux et comptes. N’accédez pas aux données d’autrui et ne dégradez pas le service.
  • Nous n’engagerons pas de poursuites contre une recherche menée de bonne foi dans le respect de ces règles.
  • Contact lisible par machine : /.well-known/security.txt.

Les clients de l’offre Entreprise reçoivent un dossier d’évaluation de sécurité (réponses aux questionnaires, sous-traitants, flux de données). DPA · Confidentialité