Safe — ein Passwort-Management-Tool

Ich habe gestern begonnen, ein eigenes Tool zum Verwalten von Zugangsdaten (Logins, Passwörter) zu schreiben. Vermutlich war das gar nicht mal so eine gute Idee, aber es hat mich getrieben, und so ward es geschehen.

Screenshot meines Web-Clients (in Arbeit)
Screenshot meines Web-Clients (in Arbeit)

Warum?

Das Problem “Zugangsdaten verwalten” wurde bereits mehrfach gelöst, warum also nicht einfach eine der bestehenden Lösungen nehmen? Nun, zum einen bin ich ein unverbesserlicher Räder-Neuerfinder. Zum anderen bin ich spätestens seit Edward Snowden ziemlich misstrauisch, eher sogar paranoid, was die Geheimhaltung von Daten betrifft. Bevor ich meine Logins einer Software wie 1Password anvertraue, von der ich nicht weiß, was genau sie damit anstellt, baue ich lieber etwas eigenes, was ich wenigstens vollständig verstehe und durchschaue. Und wenn es schief geht, muss ich mich nur über mich selbst ärgern.

Klug ist das trotzdem nicht, denn wenn man nicht ganz genau weiß, was man tut, kann bei so einem Unterfangen einiges in die Hose gehen. Die Wahrscheinlichkeit, dass ich mir hier eine Krücke baue, die unsicherer ist als alle bestehenden Lösungen, ist groß. Da ich aber ein bisschen irre bin, habe ich gesagt “scheisst der Hund drauf” und es trotzdem gemacht.

Anforderungen

  • Zugangsdaten und Codes aller Art (Website-Logins, Softwarelizenzen etc.) speichern und bearbeiten
  • Möglichkeit, die Zugangsdaten mit einem zentralen Speicherort (“Cloud”) zu synchronisieren, damit man von mehreren Geräten aus darauf zugreifen kann

Konzept

Die Datenbank

Das Tool (Arbeitstitel Safe) ist im Kern einfach nur eine Liste aus Datensätzen im JSON-Format. Jeder Datensatz bildet ein Login (oder Lizenzcode etc.) ab und umfasst folgende Felder:

  • Name (Titel) – sollte möglichst deskriptiv sein, da dies das primäre Feld ist, über das man einen Datensatz sucht
  • Typ (Art des Datensatzes, z.B. Website-Login, Softwarelizenz, WLAN-Key, SSH-Zugang, etc.)
  • URL (z.B. für Website-Logins)
  • User-ID (Benutzername oder E-Mail-Adresse)
  • Passwort
  • Notiz (um weitere Informationen unterzubringen, die in den anderen Feldern nicht erfasst werden können)
  • Zugriffsprotokoll (Liste von Timestamps für jeden Lese- und Schreibzugriff) – das erlaubt UI-Nettigkeiten wie die Anzeige der am häufigsten oder zuletzt geöffneten oder geänderten Einträge

Alle Felder sind optional, aber typischerweise hat ein Eintrag wenigstens einen Namen, User-ID und Kennwort. (Wahrscheinlich sollte ich das Namensfeld nicht-optional machen.) Ein weiteres Problem, für das ich noch keine saubere Lösung habe, ist der Umstand, dass man gerade für Website-Logins üblicherweise die E-Mail-Adresse als User-ID hat, es aber oft auch einen separaten Benutzernamen gibt, mit dem man sich ebenfalls anmelden kann. Soll ich zwei User-ID-Felder (E-Mail, Username) sichern?

Die Felder User-ID und Passwort dürfen selbstverständlich nicht im Klartext vorliegen, sondern werden mit einem erprobten Verfahren 2-Weg-verschlüsselt abgelegt. Welches Verfahren das ist, ist letztlich egal, so lange es ausreichend sicher ist. Um User-ID und Passwort lesen zu können, müssen diese Daten zunächst entschlüsselt werden, wozu der User seinen selbst gewählten Schlüssel eingeben muss. Dieser Schlüssel wird natürlich an keiner Stelle in der Software gespeichert, sondern sollte sich idealerweise nur im Kopf des Users befinden. Allerdings wird der Schlüssel notwendigerweise temporär im Speicher der Software (und des Betriebssystems, etc.) auftauchen, wo er potenziell abgefangen und ausgelesen werden könnte. (Das ist der eine Aspekt, über den ich noch am meisten grüble.)

Alle anderen Felder sind zunächst unverschlüsselt. Im Fall, dass die JSON-“Datenbank” in falsche Hände gelangt, erlangen Dritte das Wissen, wo ich überall Logins habe, aber ohne den Schlüssel können sie sich nicht anmelden, um an meine dort vorhandenen Daten zu kommen. Ich bin noch unschlüssig, ob es zulässig ist, diese “Metadaten” so ungeschützt zu lassen; im aktuellen Konzept ist es so.

Der Client

Um diese Daten vernünftig zu nutzen, benötige ich ein Programm, das mir eine Benutzerschnittstelle bereitstellt. Mit diesem kann ich neue Datensätze anlegen sowie bestehende anzeigen, bearbeiten und löschen. Wenn ich die Zugangsdaten für ein bestimmtes Ding suche (typischerweise eine Website), dann gebe ich ein paar Buchstaben in ein Suchfeld ein, und das Programm zeigt mir die Treffer an (sofern existent). Ich klicke dann auf den gesuchten Eintrag, und dieser wird mir angezeigt, allerdings ohne User-ID und Passwort, denn diese sind zu diesem Zeitpunkt noch verschlüsselt. Um sie zu entsperren, werde ich aufgefordert, meinen Schlüssel einzugeben, woraufhin sie im Klartext erscheinen und ich sie bequem von dort kopieren und in das Login-Formular der Website einfügen kann. Sofort anschließend sollten User-ID und Passwort wieder ausgeblendet und der Klartext aus dem Speicher des Programms getilgt werden. Es werden immer nur User-ID und Passwort des aktuell angezeigten Datensatzes vorübergehend entschlüsselt.

Der Client kann nativ für das jeweilige Plattform-Betriebssystem geschrieben werden, z. B. in meinem Fall eine Mac OS X-Desktop-Anwendung. Leider sind meine Fähigkeiten in der nativen Softwareentwicklung zu limitiert, so dass ich einen Client in Form einer Web-App geschrieben habe, die lokal (!) auf dem System läuft. Dieser Client ist etwa halb fertig (siehe Screenshot am Anfang des Artikels). Ich wollte schnell ein Ergebnis, daher habe ich die Technologien genutzt, die ich einigermaßen gut kenne, und das ist PHP (via MAMP als Server-Umgebung). Ich habe das Fat Free Framework für den Back-End-Teil benutzt (Routing, Template-Engine) sowie Twitter Bootstrap für das Front-End (mit dem United-Theme von Bootswatch).

Das Fat Free Framework ist extrem leichtgewichtig (ich nutze nur 2 Dateien aus dem Gesamtpaket für die Funktionalität, die ich brauche, zusammen gerade mal 70 kB). Zu Bootstrap muss ich wohl nicht viel sagen – damit lassen sich sehr, sehr schnell ansprechende Web-Interfaces bauen. Ich habe aktuell deutlich unter 500 Codezeilen selbst geschrieben (PHP und HTML) – das bleibt wirklich alles übersichtlich. Wenn die Anwendung fertig ist, werden es vielleicht 1000 Zeilen sein.

Für die 2-Weg-Verschlüsselung in PHP wird die mcrypt-Bibliothek zum Einsatz kommen. Etwas Recherche stieß mich auf eine kleine Hilfsklasse, mit der das recht einfach vonstatten gehen wird – ich hoffe zumindest, dass ich diesem Code vertrauen kann.

Cloud-Synchronisation

Ich will meine Zugangsdaten von mehreren Rechnern aus im Zugriff haben, also braucht es einen zentralen Speicherort, mit dem sich die lokalen Clients abgleichen können, damit alle auf dem selben Datenstand sind. Da ich einen Shared Webspace habe, bietet es sich an, diesen zu nutzen. (Da halte ich solche Daten für besser aufgehoben, als z. B. bei einem Dienst, in dessen Aufsichtsrat eine Condoleeza Rice sitzt. Außerdem: decentralize!)

Die Clients arbeiten immer auf ihrer lokalen Kopie der Datenbank und synchronisieren diese mit der Datenbank auf dem Webspace. Wenn man die Daten dort eh schon hat, würde es sich ja anbieten, diese gar nicht mehr lokal vorzuhalten, sondern nur noch auf dem Webspace, und Anfragen direkt dort hin zu schicken. Dazu müsste ich aber meinen Schlüssel übers Internet schicken, und die Daten würden (temporär) unverschlüsselt auf dem Webspace liegen, und das ist mir deutlich zu riskant. Tatsächlich will ich die Datenbank sogar komplett verschlüsseln, bevor sie zum Webspace geschickt wird, denn ich habe auch schon kein gutes Gefühl dabei, dass die Metadaten dort ungeschützt herumliegen, selbst wenn User-ID und Passwort verschlüsselt sind.

Was also im Client bei der Synchronisation passieren soll, ist folgendes: der Client lädt die verschlüsselte Datenbank vom Webspace herunter, und entschlüsselt sie lokal. Die lokale und die Server-Version werden abgeglichen; dabei “gewinnt” immer der Datensatz mit dem neueren Datenstand, es sei denn, derselbe Datensatz wurde lokal und auf der Server-Version geändert – bei einem solchen Merge Conflict muss der Client dem User beide Versionen zeigen, und dieser muss entscheiden, welche die Richtige ist. Anschließend werden beide Datenbank-Stände zu einer Datenbank zusammengeführt, diese wird verschlüsselt und auf den Webspace hochgeladen.

Zur Verschlüsselung der Datenbank werde ich einen eigenen Schlüssel nehmen, der im Client hinterlegt ist (als Hash, also selbst einwegverschlüsselt). Das Verschlüsselungsverfahren wird dasselbe sein, mit dem auch innerhalb der Datenbank die User-ID und Passwort verschlüsselt werden. Der Schlüssel wird vom User gewählt und kann jederzeit geändert werden (in einem Einstellungsbereich des Clients); alle Clients müssen natürlich denselben Schlüssel kennen, damit die Cloud-Synchronisation funktionieren kann.

Wenn die Datenbank vollständig verschlüsselt ist, ist der Transport übers Internet nicht mehr so kritisch. Der Transport kann dann sogar unverschlüsselt passieren; ich brauche also kein SSL. Jeder kann die Daten zwar mitlesen, und falls jemand in den Webspace einbricht, kann die Datenbank kopiert werden. Sofern das Verschlüsselungsverfahren jedoch sicher ist, ich keinen Fehler bei der Implementation mache, und der gewählte Schlüssel stark genug ist (und nur ich ihn kenne), sind die Daten trotzdem sicher.

Fragen und Probleme

Ich habe viele Szenarien gedanklich durchgespielt, was alles schief gehen kann. Unter der Voraussetzung, dass ich nicht selbst eine Lücke hineinprogrammiere, wo sind die möglichen Einfallstore?

So lange die zu schützenden Daten verschlüsselt sind, sind sie sicher. Gefährlich kann es nur während der Entschlüsselung werden. Zum einen muss ich früher oder später meinen Schlüssel in den Client eingeben, damit User-ID und Passwort entschlüsselt werden können. Da mein Client eine Web-Anwendung ist, wandert mein Schlüssel im Klartext durch das HTML-Eingabeformular, den Browser, das Betriebssystem (zum Transport innerhalb des lokalen Netzwerks auf meinem Rechner), den Webserver (Apache), PHP, und meinen Back-End-Code. Das ist ziemlich viel Gelegenheit, den Schlüssel abzufangen, sofern irgendjemand Fremdes Zugriff auf mein System hat oder dieses mit irgendeiner Malware infiziert ist. Leider ist mein Wissen recht beschränkt, was man tun könnte, um dies sicherer zu machen. (Sind das eigentlich übliche Risiko-Abwägungen, oder bin ich zu paranoid?)

Der erste Einwand wird vermutlich sein, den Client nicht als Web-Anwendung zu bauen, und dazu kann ich nur mit verzogenen Mundwinkeln zustimmend nicken. Der zweite Einwand wird lauten, dass eine hirnrissige Idee war, so ein Tool überhaupt selbst bauen zu wollen. Hierzu nicke ich ebenfalls, mit schon dezent wahnsinnigem Gesichtsausdruck (so Dr. Emmet Brown-mäßig).

Vor einiger Zeit habe ich in MAMP Pro investiert und kann damit für die lokale Web-Anwendung (den Client) per Mausklick SSL aktivieren (über sein selbst signiertes Zertifikat). Das reduziert immerhin die Strecke, die der Schlüssel im Klartext auf dem System zurücklegt. Eine weitere Überlegung ist, den Schlüssel umgehend zu hashen (reicht da ein sha1()?), sobald er aus dem POST-Request in meiner PHP-Anwendung ankommt, und nicht den Klartext-Schlüssel, sondern nur diesen Hash zu verwenden, um die User-ID und Passwort zu verschlüsseln. Auch dies sollte hoffentlich die Vorkommen und Dauer verkleinern, in der der Schlüssel im Klartext im RAM oder irgendwelchen PHP-internen Caches herumfliegt.

Feedback?

Mich würde interessieren, was Ihr zu diesem Vorhaben sagt – besonders, wenn es über “YOU ARE SILLY AND YOU HAVE NO IDEA WHAT YOU’RE DOING” hinausgeht.

Advertisements

Author: schoschie

I like to see the wiring under the board™

5 thoughts on “Safe — ein Passwort-Management-Tool”

  1. Danke Schoschie für diese Einblicke. Ich denke, es kann nicht genug Tools geben, insofern finde ich jede Neuentwicklung erstmal gut. Was mir fehlt (1Password-Nutzer) ist eine integrierte Lösung zum Versand von Passwörtern. Beispiel: Auftraggeber will 5 Mailboxen, 2 FTP-Accounts, wasauchimmer eingerichtet haben. Klassischer, richtiger Weg wäre, die (generierten) Passwörter auszudrucken und per Briefpost zu verschicken. Ganz doof: per E-Mail, per Skype. Nett wäre es, ich trage die PWs in meinen Manager ein, klicke „versenden“, wähle die E-Mail-Adresse des Auftraggebers. Und dann? Der könnte nur ein Token verschickt bekommen (URL und zweiten Schlüssel habe ich per Telefon angekündigt) womit er sich in den Save einloggen kann und dann nur das Passwort gezeigt bekommt. (keine URL, Server, Username). Macht so was für Dich Sinn?

    1. Danke für Dein Feedback 🙂 Für die beschriebene Anwendung könnte ich mir eher ein separates Tool vorstellen, das nicht erst lokal installiert und eingerichtet werden muss (wie mein aktuelles Selbstbau-Experiment).

      Das könnte man weiter abstrahieren auf einen Webservice, der beliebige geheimzuhaltende Informationen bereitstellen kann, nicht nur Passwörter. Wenn man es so konstruiert, dass die übertragene Information nur ein einziges Mal angezeigt werden kann (und anschließend gelöscht wird), kann man sich sogar den Key sparen:

      X will Y etwas mitteilen (in Deinem Beispiel Du=X, Kunde=Y, Inhalt: Einen Satz Passwörter für einen Webspace). Dazu trägt X die Daten in das Tool ein, zusammen mit der Mailadresse von Y. Die Daten werden per SSL auf den Server des Tools übertragen und dort mit einem anwendungs-internen Key verschlüsselt. Das Tool erzeugt eine URL mit einem Einmal-Token (Hash), die Y per Mail gesendet wird.

      Y öffnet die Mail, klickt auf die URL, und wird zum Eintrag mit den Daten geleitet (übertragen per SSL). Y hat jetzt einige Momente Zeit, die Daten bei sich zu sichern, anschließend wird der Eintrag automatisch aus dem Tool gelöscht (die Daten verschwinden vom Server, zusätzlich wird das Browserfenster geschlossen – erfordert natürlich JavaScript aktiv beim Client).

      Da die Token-URL nur einmal genutzt werden kann, kann man sicher sein, dass die Daten in falsche Hände geraten sind, wenn der Eintrag nicht mehr existiert. Es müssen dann neue Daten erzeugt werden.

      Man könnte noch weitere Schranken einbauen, z.B. dass die Token-URL innerhalb einer gewissen Zeitspanne geöffnet werden muss, sonst wird der Eintrag ebenfalls gelöscht.

      Das ist nur eine Idee, ich habe es nicht bis in alle Eventualitäten durchdacht, und ich bin kein Krypto-Experte. Vermutlich gibt es so etwas eh schon, mal googeln?

  2. Danke für die Antwort. Ich dachte nur, dass man das Passwort-Weitergeben-Tool dann braucht, wenn man das Passwort-Speichern-Tool hat, insofern eine Integration Sinn macht. Aber Deine Argumentation ist auch nachvollziehbar und so kann man es auch machen (ich bleib’ dann erstmal beim Papier). Viel Spaß beim Weiterentwickeln …

    1. Danke für den Hinweis. Ich kenne Bruce Schneier, und habe auf seiner Site mindestens einen Artikel vor einer Weile gelesen, wo es um Passwort-Manager geht. Wahrscheinlich hat der sogar meinen Artikel (mit) inspiriert. Ist auf jeden Fall eine gute Quelle für kritische Betrachtungen.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s