Termiyo

Sicherheit

Wie der Tresor funktioniert

Kein Gerede: hier stehen die tatsächlichen Konstruktionen, die Parameter, und warum jede so gewählt ist.

Wogegen wir verteidigen

Drei Situationen formen jede Entscheidung unten. Ein Sync-Server, der deine Daten speichert und sie nie lesen können sollte. Ein gestohlener Laptop, bei dem die Datenbankdatei in fremden Händen ist. Und ein Angreifer, der diese Datei offline hat und so schnell Vermutungen dagegen laufen lässt, wie die Hardware es zulässt.

Die dritte entscheidet über die Schlüsselableitung, denn sie ist die einzige, in der das Budget des Angreifers das Tempo setzt und nicht dein Passwort.

Ein zweiter Faktor, und wofür er da ist

Die Zwei-Faktor-Anmeldung schützt das Konto, nicht den Tresor, und dieser Unterschied wiegt schwerer, als er klingt. Ein gestohlenes oder erratenes Passwort reicht dann nicht mehr, um ein neues Gerät anzumelden und deine versiegelten Schlüssel herunterzuladen — das verschlüsselte Bündel und, weil dasselbe Passwort den Schlüssel dazu ableitet, alles darin. Genau diesen Angriff hält ein Code auf.

Um einen Tresor auf einem Rechner zu öffnen, den jemand bereits hat, reicht es weiterhin. Der Tresor ist hier verschlüsselt, auf deiner eigenen Platte, ohne Server dazwischen, den man etwas fragen könnte — dort gibt es also nichts, was ein Code bewachen könnte. Die Zwei-Faktor-Anmeldung meldet außerdem bereits angemeldete Geräte nicht ab und macht ein vergessenes Passwort nicht wiederherstellbar.

Beim Einschalten bekommst du zehn Wiederherstellungscodes zu sehen — einmal. Sie und jeder noch angemeldete Rechner, auf dem sich der Faktor mit deinem Passwort ausschalten lässt, sind die zwei Wege zurück, wenn deine Authenticator-App weg ist. Einen dritten gibt es nicht: niemand hier kann dich an einem Faktor vorbeiwinken, weil es auf unserer Seite nichts gibt, womit das ginge.

Argon2id, kein schneller Hash

Dein Master-Passwort wird mit Argon2id bei 64 MiB Speicher und drei Durchgängen zu einem 32-byte Schlüssel gestreckt — libsodiums `crypto_pwhash`, das Argon2id in einer einzigen Spur ausführt. Der Speicher ist der Punkt: eine GPU kann gewaltige Mengen Hash-Operationen parallel rechnen, aber sie kann jeder davon nicht 64 MiB schnellen Speicher geben. Das macht aus einem breiten parallelen Angriff wieder einen schmalen.

Zum Vergleich: eine PBKDF2-SHA256-Ableitung mit tausend Iterationen — noch immer ein verbreiteter Standard — kostet einen Angreifer unter einer Millisekunde pro Versuch und parallelisiert fast perfekt. Argon2id mit diesen Parametern braucht auf einem Laptop rund 130 ms und widersteht genau dieser Parallelität.

Die Parameter stehen neben dem Tresor, sie später zu erhöhen betrifft also neue Ableitungen, während bestehende Tresore weiter aufgehen.

Jeder Datensatz einzeln versiegelt

Jeder Tresor hat seinen eigenen zufälligen 32-byte Schlüssel, eingepackt unter dem Master-Schlüssel. Datensätze werden mit XChaCha20-Poly1305 verschlüsselt, mit einer frischen 24-byte Nonce, und die eigene Identität des Datensatzes — Typ, Tresor und id — wird als associated data hineingebunden.

Der letzte Teil wiegt mehr, als er klingt. Ohne ihn könnte jeder mit dem Geheimtext einen gültigen verschlüsselten Block auf einen anderen Datensatz schieben, und der Client würde ihn annehmen. Mit ihm geht ein umbenannter Datensatz einfach nicht auf.

Teilen, ohne einen Schlüssel herzugeben

Jedes Konto hat ein X25519-Schlüsselpaar. Einen Tresor zu teilen versiegelt seinen Schlüssel auf den öffentlichen Schlüssel des Empfängers, ein Server kann also verwalten, wer auf was Zugriff hat, ohne jemals einen Schlüssel zu halten, der etwas öffnet.

Zugriff zu entziehen entfernt die versiegelte Kopie und beendet die Synchronisierung. Was die Person schon hat, erreicht das nicht: Wer die Daten schon gelesen hat, hat sie gelesen, und kein System kann das zurücknehmen. Auch den Schlüssel des Tresors ändert der Entzug nicht — Termiyo kann das nicht —, also behält jemand, der synchronisiert hat, während er „Darf bearbeiten“ hatte, einen Schlüssel, der alles öffnet, was später in diesem Tresor gespeichert wird, wo immer diese Datensätze ihn erreichen; teilt man den Tresor wieder mit ihm, selbst als „Nur lesen“, bekommt er mindestens dessen Hosts. Ein Geheimnis holt nur zurück, wer die Passwörter und Schlüssel auf den Servern selbst ändert.

Host-Schlüssel, gepinnt

Wenn Termiyo einen Server zum ersten Mal sieht, zeigt es dir den Schlüssel und seinen SHA-256-Fingerprint und pinnt, was du annimmst. Jede neue Verbindung wird gegen diesen Pin geprüft.

Ändert sich ein Schlüssel, sagt Termiyo das deutlich statt es zu verstecken: ein neu aufgesetzter Server und eine abgefangene Verbindung sehen für Software gleich aus, und nur du weißt, welches von beiden du erwartet hast.

Wo die Geheimnisse wirklich liegen

Verbindungen laufen in einem von der Oberfläche getrennten Prozess. Das Fenster, das dein Terminal zeichnet, hat keinen Netzwerkzugriff, keinen Dateisystemzugriff und bekommt nie ein Passwort oder einen privaten Schlüssel — es bittet darum, sich mit einem gespeicherten Host per Name zu verbinden, und ein anderer Prozess entscheidet, was das heißt.

Alles, was in der Oberfläche gezeigt wird, ist vorher maskiert. Einen Datensatz mit einem maskierten Feld zurückzuspeichern lässt das gespeicherte Geheimnis unberührt.

Prüfen, was du heruntergeladen hast

Zwei verschiedene Prüfungen, und sie beantworten verschiedene Fragen. Der SHA-256 neben jedem Download auf der Download-Seite sagt dir, dass die Bytes, die du hast, die Bytes sind, die wir gebaut haben: `shasum -a 256 <file>` auf macOS und Linux, `certutil -hashfile <file> SHA256` auf Windows.

Die Signatur sagt dir, wer sie gebaut hat, und dein Betriebssystem prüft sie für dich, bevor es die App startet. Du kannst sie vorher selbst prüfen. Auf macOS: `spctl -a -t open --context context:primary-signature -vv <file>.dmg` sollte "accepted" mit "source=Notarized Developer ID" antworten.

Der Windows-Installer ist unsigniert, deshalb gibt es unter Eigenschaften keinen Reiter Digitale Signaturen. Aus dem fehlenden Reiter lässt sich nicht erkennen, ob die Datei verändert wurde. Speichere den Installer, ohne ihn auszuführen, und führe dann `certutil -hashfile "<file>" SHA256` aus. Ersetze `<file>` durch den Pfad der gespeicherten Datei. Vergleiche das Ergebnis mit dem SHA-256 neben genau diesem Download auf der Download-Seite, bevor du den Installer öffnest. Weichen sie ab, führe ihn nicht aus. Ein übereinstimmender Hash bestätigt, dass die Bytes unserer veröffentlichten Datei entsprechen; er ist keine Herausgebersignatur. Anders als beim Linux-Fall weiter unten ist das eine Lücke von uns und keine Eigenschaft der Plattform: Windows prüft Signaturen einwandfrei, wir haben ihm noch keine zum Prüfen gegeben. Diese Seite wird das so lange schreiben, bis der Installer, den du herunterlädst, eine Signatur trägt, die du selbst prüfen kannst.

Auf Linux gibt es kein Gegenstück — ein .deb oder ein AppImage trägt keine Signatur, die dein System prüft, also ist der Hash alles, was du überprüfen kannst. Das ist eine Eigenschaft der Plattform und nicht unsere Wahl, und es ist besser, das zu wissen, als das Gegenteil anzunehmen.

Was deine Maschine verlässt

Zwei Dinge, und beide sind aufgelistet. Termiyo sendet höchstens einmal in 24 Stunden einen kurzen Bericht über sich selbst — Version, Plattform, Prozessor, Art der Installation, Sprache der Oberfläche, ob nach Updates gesucht wird, und eine Zahl der Absturzberichte in seinem eigenen Ordner — ohne Kennung und ohne irgendetwas aus deinen Sitzungen darin; er ist standardmäßig eingeschaltet, und ein Klick schaltet ihn aus, beim ersten Start oder unter Einstellungen → Hilfe. Ein Absturz schreibt einen Dump in einen Ordner auf deiner eigenen Platte, und uns einen davon zu schicken ist ein eigener Schalter, der aus bleibt, bis du ihn einschaltest; Einstellungen → Hilfe nennt ihn, sagt, was ein Dump enthalten kann, und öffnet den Ordner.

Uns einen zu schicken ist ein Schalter auf diesem Bildschirm. Er ist bei einer frischen Installation aus, nach einem Update aus, und solange er aus ist verlässt kein Dump die Maschine — ihn selbst an einen Fehlerbericht zu hängen ist weiterhin der einzige Weg. Schalte ihn ein: Wenn „Beim Start von Termiyo nach Aktualisierungen suchen“ eingeschaltet ist, lädt der nächste Absturz seinen Dump über HTTPS hoch, dazu den Namen, den deine eigene Maschine dieser Datei gegeben hat, die Version, die Plattform, die Prozessorarchitektur und eine Kennung für diese Installation, die bei diesem ersten Upload erzeugt wird, und nichts weiter; derselbe Bildschirm listet das Gesendete auf und hat eine Schaltfläche, die unseren Server bittet, es zu löschen. Hier stand früher, Crash-Reporting sei abwesend und nicht bloß abgeschaltet — was für jeden Build vor dem galt, der die Adresse hinzugefügt hat. Die Details stehen auf der Datenschutzseite. Ist die Update-Prüfung abgeschaltet, wartet ein Dump, dessen Versand du zugestimmt hast, auf dieser Maschine und geht beim ersten Start, nachdem die Prüfung wieder an ist.

Mit abgeschalteter Update-Prüfung wird der Updater nie geladen: die Bibliothek wird erst bei der ersten Nutzung importiert, mit abgeschalteter Prüfung ist das Modul also nie da und hat nichts, womit es eine Anfrage stellen könnte. So weit ist das strukturell und kein Versprechen über einen Zweig im Code.

Was wir hier falsch hatten und korrigieren: Hier stand, dass ein Start mit abgeschalteter Prüfung überhaupt keine Anfrage nach außen stellt, und tcpdump wurde als der Weg angeboten, das nachzusehen. Ein Start, den niemand anfasst, ist mit abgeschalteter Prüfung inzwischen tatsächlich still — auf der Leitung gemessen, unter Linux —, aber sobald der Tresor aufgeht, entsteht Verkehr, der mit der Update-Einstellung nichts zu tun hat, und diese Seite hat davon nur einen Teil genannt. Das Erste sind die Terminals, die du offen gelassen hast: SSH-Tabs, die beim letzten Schließen von Termiyo noch offen waren, werden wieder geöffnet, sobald der Tresor aufgeht, jeder mit einer vollständigen Anmeldung bei seinem Host — das bringt deine Arbeit dahin zurück, wo du sie gelassen hast, und ein Tab, den du vor dem Beenden schließt, kommt nicht von selbst wieder. Ist niemand angemeldet, fragt der Erststart-Bildschirm, bis du das Angebot eines Kontos beantwortet hast, ob termiyo.com antwortet, damit er weiß, ob es sich lohnt, dir ein Konto anzubieten — einmal pro Start, beim ersten Entsperren; solange termiyo.com nicht erreichbar ist, wird das Angebot nicht gemacht, also fragt der nächste Start wieder. Bist du angemeldet, fragt Termiyo, ob deine Adresse bestätigt ist — einmal pro Start und ein zweites Mal, solange sie es nicht ist, weil das Fenster, das dann nach deinem Code fragt, die Antwort noch einmal liest —, synchronisiert, wenn der Tresor aufgeht, und danach alle fünf Minuten, fragt beim Öffnen des Formulars für einen Host, eine Gruppe oder einen Proxy, in welchem deiner Tresore der Eintrag gespeichert werden kann, und fragt — wenn du keinen eigenen KI-Schlüssel hast —, wie viel vom KI-Kontingent deines Kontos übrig ist, sobald du das KI-Panel öffnest oder in einem Terminal zu tippen beginnst. Solange die Host-Liste offen ist, wird jeder gespeicherte SSH- oder Telnet-Host, den Termiyo direkt erreichen kann, alle 15 Sekunden geprüft — eine Verbindung zu seinem Port, die ohne ein einziges Byte wieder geschlossen wird —, damit der Punkt daneben stimmt; diese Verbindungen gehen an deine Server, nicht an uns, und tauchen in deren Logs auf. Ein Host, der unter einem Namen statt unter einer Adresse gespeichert ist, kostet dabei jedes Mal auch eine DNS-Anfrage, und die geht an den Resolver, den dein Rechner benutzt. Die Host-Liste auszublenden stoppt diese Prüfungen, aber nicht eine weitere derselben Art: Solange vorne ein Terminal ist, das mit einem dieser Hosts verbunden ist, prüft die Statusleiste diesen Host alle 10 Sekunden für die Latenz, die sie anzeigt — mit oder ohne Liste —, solange die Leiste „Verbunden“ zeigt, und fragt bei einem per Namen gespeicherten Host jedes Mal auch deinen Resolver nach ihm. Und was du eingerichtet hast, tut, wofür du es eingerichtet hast: Eine geplante Sicherung kopiert sich auf den Spiegel, den du angegeben hast, Webhooks rufen ihre Adressen auf, und geplante Aufgaben und Weiterleitungen verbinden sich mit ihren Hosts — eine geplante Aufgabe einmal pro Lauf, und sie meldet sich wieder ab, sobald ihr Snippet fertig ist. Die Behauptung war also in genau der einen Form falsch, von der wir gesagt haben, sie sei es wert: in der, die du selbst nachsehen kannst.

Ein Terminal, das du teilst, ist ein zweiter Ort, an dem die Session existiert, und dieser zweite Ort ist ein Browser-Tab. Die Bytes gehen von deinem Rechner zu dem des anderen und durch nichts sonst: kein Relay trägt sie, und das ist eine Entscheidung — ein TURN-Server würde den Verkehr sehen, also benutzt Termiyo auf keiner der beiden Seiten einen, und unser eigener Server stellt nur den Kontakt zwischen euch beiden her. Was wir benutzen, ist öffentliches STUN, das von Google und das von Cloudflare, um zu fragen, wie deine Adresse von außen aussieht — ein Host hinter NAT ist sonst nicht erreichbar; diese beiden erfahren diese Adresse, und nichts weiter. Die Gast-Seite fragt überhaupt keinen STUN-Server, damit niemandem die Adresse von jemandem gegeben wird, der sich nicht entschieden hat, etwas zu teilen. Dann der Preis: ein Gast sieht in einem Browser zu, also können Erweiterungen diese Seite lesen, und der Browser kann ein Bild davon für eine Tab-Vorschau behalten. Ein Gast beginnt nur lesend und kann nicht tippen, bis du es erlaubst, und die Freigabe endet, wenn du sie beendest, oder nach vier Stunden. Was sie nicht ist: derselbe Schutz, den die App selbst gibt. Und die Gast-Seite sagt das auf dem eigenen Bildschirm des Gastes und nicht nur hier.

Was wir nicht behaupten können: die SQLite-Datei selbst ist nicht verschlüsselt, nur die Datensätze darin. Wer die Datei hat, erfährt, wie viele Hosts du hast, wann du jeden zuletzt angefasst hast und welche Namen du ihnen gegeben hast. Ihre Adressen, Benutzernamen, Passwörter und Schlüssel sind verschlüsselt. Das sagen wir hier lieber, als dass du es herausfindest.

Etwas gefunden?

Sicherheitsmeldungen gehen an info@termiyo.com. Wir bestätigen den Eingang innerhalb von zwei Werktagen.