Sécurité
Comment fonctionne le coffre
Sans esquive : voici les constructions réelles, les paramètres, et pourquoi chacun a été choisi.
Contre quoi nous nous défendons
Trois situations façonnent chaque décision ci-dessous. Un serveur de synchronisation qui stocke vos données et ne devrait jamais pouvoir les lire. Un portable volé, dont le fichier de base de données est entre les mains de quelqu’un d’autre. Et un attaquant avec ce fichier hors ligne, qui enchaîne les hypothèses aussi vite que le matériel le permet.
C’est la troisième qui décide de la dérivation de clé, parce que c’est la seule où le rythme est fixé par le budget de l’attaquant et non par votre mot de passe.
Un second facteur, et à quoi il sert
La connexion à deux facteurs protège le compte, pas le coffre, et la différence compte plus qu’il n’y paraît. Un mot de passe volé ou deviné ne suffit plus à connecter un nouvel appareil et à récupérer vos clés scellées — le paquet chiffré et, parce que ce même mot de passe dérive la clé qui l’ouvre, tout ce qu’il contient. C’est cette attaque-là qu’un code arrête vraiment.
Il suffit toujours à ouvrir un coffre sur une machine que quelqu’un possède déjà. Le coffre est chiffré ici, sur votre propre disque, sans aucun serveur à qui demander quoi que ce soit : il n’y a donc rien là qu’un code puisse garder. La double authentification ne déconnecte pas non plus les appareils déjà connectés, et elle ne rend pas un mot de passe oublié récupérable.
En l’activant, vous voyez dix codes de secours, une seule fois. Ces codes, et toute machine encore connectée — sur laquelle le facteur se désactive avec votre mot de passe — sont les deux chemins de retour si votre application d’authentification disparaît. Il n’y en a pas de troisième : personne ici ne peut vous faire passer outre un facteur, parce qu’il n’y a rien de notre côté qui le permette.
Argon2id, pas un hachage rapide
Votre mot de passe maître est étiré en une clé de 32-byte avec Argon2id à 64 MiB de mémoire et trois passes — le `crypto_pwhash` de libsodium, qui exécute Argon2id sur une seule voie. La mémoire est le point clé : un GPU peut exécuter un nombre énorme d’opérations de hachage en parallèle, mais il ne peut pas donner 64 MiB de mémoire rapide à chacune. Cela ramène une attaque parallèle large à une attaque étroite.
À titre de comparaison, une dérivation PBKDF2-SHA256 à mille itérations — encore une valeur par défaut courante — coûte à l’attaquant moins d’une milliseconde par hypothèse et se parallélise presque parfaitement. Argon2id avec ces paramètres prend environ 130 ms sur un portable et résiste précisément à ce parallélisme.
Les paramètres sont enregistrés à côté du coffre : les relever plus tard touche les nouvelles dérivations tandis que les coffres existants s’ouvrent toujours.
Chaque enregistrement scellé à part
Chaque coffre a sa propre clé aléatoire de 32-byte, enveloppée sous la clé maîtresse. Les enregistrements sont chiffrés en XChaCha20-Poly1305 avec un nonce neuf de 24-byte, et l’identité de l’enregistrement lui-même — son type, son coffre et son id — est liée en associated data.
Ce dernier point compte plus qu’il n’y paraît. Sans lui, quiconque détient le chiffré pourrait déplacer un bloc chiffré valide vers un autre enregistrement et le client l’accepterait. Avec lui, un enregistrement réétiqueté ne s’ouvre tout simplement pas.
Clés d’hôte, épinglées
La première fois que Termiyo voit un serveur, il vous montre la clé et son empreinte SHA-256, et épingle celle que vous acceptez. Chaque reconnexion est vérifiée contre cet épinglage.
Quand une clé change, Termiyo le dit franchement au lieu de l’enterrer : un serveur réinstallé et une connexion interceptée sont identiques pour un logiciel, et vous seul savez lequel des deux vous attendiez.
Où vivent réellement les secrets
Les connexions tournent dans un processus séparé de l’interface. La fenêtre qui dessine votre terminal n’a ni accès au réseau ni accès au système de fichiers, et ne reçoit jamais un mot de passe ni une clé privée : elle demande à se connecter à un hôte enregistré par son nom, et un autre processus décide de ce que cela veut dire.
Tout ce qui est affiché dans l’interface est masqué au préalable. Réenregistrer une fiche avec un champ masqué laisse le secret stocké intact.
Vérifier ce que vous avez téléchargé
Deux vérifications différentes, qui répondent à des questions différentes. Le SHA-256 à côté de chaque téléchargement sur la page de téléchargement vous dit que les octets que vous avez sont ceux que nous avons produits : `shasum -a 256 <file>` sur macOS et Linux, `certutil -hashfile <file> SHA256` sur Windows.
La signature vous dit qui les a produits, et votre système d’exploitation la vérifie pour vous avant de lancer l’application. Vous pouvez la vérifier vous-même d’abord. Sur macOS : `spctl -a -t open --context context:primary-signature -vv <file>.dmg` doit répondre "accepted" avec "source=Notarized Developer ID".
L’installeur Windows n’est pas signé : les Propriétés ne contiennent donc pas d’onglet Signatures numériques. L’absence de cet onglet ne permet pas de savoir si le fichier a été modifié. Enregistrez l’installeur sans l’exécuter, puis lancez `certutil -hashfile "<file>" SHA256`, en remplaçant `<file>` par le chemin du fichier enregistré. Comparez le résultat au SHA-256 à côté de ce même téléchargement sur la page de téléchargement avant d’ouvrir l’installeur. S’ils diffèrent, ne l’exécutez pas. Un hash identique confirme que les octets correspondent à notre fichier publié ; ce n’est pas une signature d’éditeur. Contrairement au cas Linux ci-dessous, c’est un manque de notre part et non une propriété de la plateforme : Windows vérifie très bien les signatures, nous ne lui en avons pas encore donné une à vérifier. Cette page continuera de le dire tant que l’installeur que vous téléchargez ne portera pas une signature que vous pouvez vérifier vous-même.
Sur Linux il n’y a pas d’équivalent : un .deb ou un AppImage ne porte aucune signature que votre système vérifie, donc le hachage est tout ce que vous pouvez contrôler. C’est une propriété de la plateforme et non un choix de notre part, et mieux vaut le savoir que supposer le contraire.
Ce qui quitte votre machine
Deux choses, et les deux sont listées. Termiyo envoie un court rapport sur lui-même au plus une fois toutes les 24 heures — version, plate-forme, processeur, mode d’installation, langue de l’interface, si la recherche de mises à jour est active, et un décompte des vidages de plantage présents dans son propre dossier — sans identifiant et sans rien de vos sessions dedans ; il est activé par défaut et un clic le désactive, au premier démarrage ou dans Paramètres → Aide. Un plantage écrit un vidage dans un dossier de votre propre disque, et nous en envoyer un est un interrupteur distinct qui reste désactivé jusqu’à ce que vous l’activiez ; Paramètres → Aide l’indique, dit ce qu’un vidage peut renfermer, et ouvre le dossier.
Nous en envoyer un est un interrupteur sur cet écran. Il est désactivé sur une installation neuve, désactivé après une mise à jour, et tant qu’il l’est aucun vidage ne quitte la machine : le joindre soi-même à un rapport de bug reste le seul chemin. Activez-le : si « Vérifier les mises à jour au démarrage de Termiyo » est activé, le prochain plantage téléverse son vidage en HTTPS, avec le nom que votre propre machine a donné à ce fichier, la version, la plate-forme, l’architecture du processeur et un identifiant pour cette installation créé lors de ce premier envoi, et rien d’autre ; le même écran énumère ce qui est parti et comporte un bouton qui demande à notre serveur de le supprimer. Ce paragraphe disait auparavant que le rapport de plantage était absent et pas seulement désactivé, ce qui était vrai de toutes les versions antérieures à celle qui a ajouté l’adresse. La page de confidentialité a le détail. Quand la vérification des mises à jour est coupée, un vidage que vous avez accepté d’envoyer attend sur cette machine et part au premier lancement après sa réactivation.
La vérification des mises à jour désactivée, le module de mise à jour n’est jamais chargé : la bibliothèque est importée à la première utilisation, donc avec la vérification coupée le module n’est jamais là et n’a rien pour émettre une requête. Cela au moins est structurel, et non une promesse sur une branche de code.
Ce que nous avions faux ici, et que nous corrigeons : il était écrit qu’avec la vérification coupée un lancement ne fait aucune requête sortante, et tcpdump était proposé comme moyen de le vérifier. Un lancement auquel personne ne touche est désormais silencieux avec la vérification coupée — mesuré sur le réseau, sous Linux —, mais l’ouverture du coffre déclenche un trafic qui n’a rien à voir avec le réglage des mises à jour, et cette page n’en nommait qu’une partie. D’abord les terminaux que vous avez laissés ouverts : les onglets SSH encore ouverts à la dernière fermeture de Termiyo sont rouverts dès que le coffre s’ouvre, chacun avec une connexion complète à son hôte — c’est ce qui remet votre travail là où vous l’aviez laissé, et un onglet que vous fermez avant de quitter ne revient pas de lui-même. Sans compte connecté, tant que vous n’avez pas répondu à l’offre d’un compte, l’écran de premier lancement demande si termiyo.com répond, afin de savoir s’il vaut la peine de vous proposer un compte — une fois par lancement, au premier déverrouillage ; tant que termiyo.com est injoignable, l’offre n’est pas faite, donc le lancement suivant redemande. Avec un compte connecté, Termiyo demande si votre adresse a été confirmée — une fois par lancement, et une fois de plus tant qu’elle ne l’est pas, parce que le panneau qui vous demande alors votre code relit la réponse —, synchronise à l’ouverture du coffre puis toutes les cinq minutes, demande dans lequel de vos coffres un hôte, un groupe ou un proxy peut être enregistré quand vous ouvrez son formulaire, et, si vous n’avez pas de clé d’IA à vous, demande ce qui reste de l’allocation d’IA de votre compte quand vous ouvrez le panneau d’IA ou commencez à taper dans un terminal. Tant que la liste des hôtes est ouverte, chaque hôte SSH ou telnet enregistré que Termiyo peut joindre directement est vérifié toutes les 15 secondes — une connexion à son port, refermée sans qu’un octet soit envoyé — pour que le point à côté soit à jour ; ces connexions vont vers vos serveurs, pas vers nous, et apparaissent dans leurs journaux. Un hôte enregistré par son nom plutôt que par son adresse coûte en plus une requête DNS à chaque fois, et celle-ci part vers le résolveur qu’utilise votre machine. Masquer la liste des hôtes arrête ces vérifications, mais pas une autre du même genre : tant que l’onglet au premier plan est un terminal connecté à l’un de ces hôtes, la barre d’état vérifie cet hôte toutes les 10 secondes pour la latence qu’elle affiche, liste ou pas, tant que la barre affiche « Connecté », et, pour un hôte enregistré par son nom, interroge aussi votre résolveur à son sujet à chaque fois. Et ce que vous avez configuré fait ce pour quoi vous l’avez configuré : une sauvegarde planifiée se copie vers le miroir que vous lui avez donné, les webhooks appellent leurs adresses, et les tâches planifiées et les redirections se connectent à leurs hôtes — une tâche planifiée une fois par exécution, en se déconnectant quand son snippet est terminé. L’affirmation était donc fausse sous la seule forme dont nous disions qu’elle valait la peine, celle que vous pouvez contrôler vous-même.
Un terminal que vous partagez est un deuxième endroit où la session existe, et ce deuxième endroit est un onglet de navigateur. Les octets vont de votre machine à la sienne et ne traversent rien d’autre : aucun relais ne les transporte, et c’est un choix — un serveur TURN verrait le trafic, donc Termiyo n’en utilise aucun, d’aucun côté, et notre propre serveur ne fait que vous mettre en relation tous les deux. Ce que nous utilisons, en revanche, c’est du STUN public, celui de Google et celui de Cloudflare, pour demander à quoi ressemble votre adresse vue de l’extérieur, parce qu’un hôte derrière un NAT est sinon injoignable ; ces deux-là apprennent cette adresse, et rien d’autre. Le navigateur de l’invité, lui, ne reçoit aucun serveur STUN : ainsi personne ne se voit remettre l’adresse de la personne qui n’a pas choisi de partager quoi que ce soit. Puis le coût : un invité regarde dans un navigateur, donc les extensions peuvent lire cette page, et le navigateur peut en garder une image pour l’aperçu de l’onglet. Un invité commence en lecture seule et ne peut pas écrire avant que vous l’y autorisiez, et le partage s’arrête quand vous l’arrêtez ou au bout de quatre heures. Ce que ce n’est pas, c’est la même protection que celle que l’application elle-même vous donne, et la page que voit l’invité le dit sur son propre écran plutôt qu’ici seulement.
Ce que nous ne pouvons pas affirmer : le fichier SQLite lui-même n’est pas chiffré, seuls les enregistrements qu’il contient le sont. Qui a le fichier apprend combien d’hôtes vous avez, quand vous avez touché chacun pour la dernière fois, et les noms que vous leur avez donnés. Leurs adresses, identifiants, mots de passe et clés sont chiffrés. Nous préférons le dire ici plutôt que vous le laisser découvrir.
Vous avez trouvé quelque chose ?
Les signalements de sécurité vont à info@termiyo.com. Nous confirmons la réception sous deux jours ouvrés.