, ,

Cloud basierter Password Manager

bs103

von Benjamin Schweizer (bs103) und Max Eichinger (me110)

Abstract

Können Passwort Manager Anbieter meine Passwörter lesen? Wir wollten auf Nummer sichergehen und haben unseren Eigenen entwickelt. Dieser Artikel zeigt auf welche Schritte wir hierfür unternehmen mussten.
Dabei haben wir unser Frontend mittels Flutter und unser Backend in AWS umgesetzt. Außerdem gehen wir auf IaC mittels Terraform ein. Am Ende teilen wir unsere Probleme bei der Umsetzung sowie Erweiterungsmöglichkeiten, welche in Zukunft umgesetzt werden könnten.

Mobile App

Für die Umsetzung des Frontends haben wir uns für das Flutter Framework entschieden. Durch Flutter konnten wir eine gemeinsame Codebasis für alle unsere Zielplattformen (iOS, Android) verwenden. Daher konnten neue Features schnell implementiert und Änderungen konnten sofort auf unterschiedlichen Geräten getestet werden. Außerdem wurde durch einen Integrationstest sichergestellt, dass die App auf beiden Plattformen fehlerfrei läuft.


Die App bietet eine einfache Benutzeroberfläche, in welcher folgende Aktionen möglich sind:

  • Login und Registrierung eines Nutzers
  • Hinzufügen und Löschen eines Passworts
  • Ändern von Passwörtern

Diese Funktionen sind in folgenden Benutzeroberflächen abgebildet

Die Oberfläche ist auf Android und iOS identisch.

Architektur

Grundlegend ist unsere Architektur in Frontend und Backend aufgeteilt. Dabei wird, wie bereits erwähnt das Frontend mit Flutter umgesetzt und das Backend über die AWS-Cloud realisiert.
Alle Anfragen an das Backend werden mit HTTP-Requests an das API-Gateway-Service gesendet.
Die Anfragen der Nutzer müssen einen validen JWT (JSON Web Token) enthalten.
Diesen Session Token bekommt der Nutzer bei erfolgreichem Log-in über den Cognito-Service.
Durch den Token kann in den Lambda Funktionen sichergestellt werden, das Nutzer nur Daten ändern können, für die Sie eine Berechtigung haben.
Die Lambda Funktionen evaluieren die Anfragen und Ändern die Passwortdaten im DynamoDB-Service.
Alle Passwortdaten, welche an das Backend übertragen werden, sind bereits lokal vom Client verschlüsselt worden, um Missbrauch zu verhindern.


AWS Services

Da wir dieses Semester bereits in einem anderen Studienfach Erfahrung mit AWS in Verbindung mit IoT sammeln konnten, war AWS unsere erste Wahl. Außerdem waren wir uns am Anfang des Projektes sicher, das AWS alle unsere Anforderungen erfüllt.

DynamoDB
AWS DynamoDB ist ein vollständig verwalteter NoSQL-Datenbankservice. Dort werden alle Passwortdaten gespeichert.
Um schnelle Query Anfragen zu ermöglichen, ist unsere Tabelle in folgende Felder aufgeteilt:

  • Partitionsschlüssel: User_Id (Eine eindeutige ID für jeden Nutzer)
  • Sortierschlüssel: PasswordName
  • Passwort (in verschlüsselter Form)
  • Beschreibung

API-Gateway

Um HTTP-Anfragen an unsere Lambda Funktionen weiterzuleiten, nutzen wir den API-Gateway-Service. Dieser validiert Nutzeranfragen auf erforderliche Parameter und lehnt bei fehlenden Daten die Anfrage ab. Außerdem wird hier der Token mithilfe von Cognito geprüft.
Wir nutzen 3 verschiedene HTTP-Methoden, um unsere Client-Anfragen zu bearbeiten. Zudem sind alle Methoden über einen API-Key gesichert.

  • Die DELETE Methode löscht ein Password von einem Nutzer.
  • Die GET Methode gibt alle Passwörter eines Nutzers zurück.
  • Die PUT Methode erstellt oder überschreibt ein Passwort.

Lambda
Innerhalb jeder unserer Lambda Funktionen haben wir Zugriff auf den Cognito Authorizer. Dieser bietet uns die Möglichkeit, direkt auf die Daten (User_Id, Username etc.) des Nutzers zuzugreifen, welcher den Request geschickt hat.

PUT Methode:

In der PUT Methode werden neue Passwörter gespeichert oder schon vorhandene überschrieben.

Durch das in API-Gateway angelegte JSON-Schema können wir prüfen, ob der HTTP-Body die erforderlichen Parameter enthält.
Trotzdem kann es sein, dass vom Nutzer ein leerer String (“”) geschickt wird.
Dies ist der erste Validierungsschritt, welcher in der Lambda Funktion ausgeführt wird.


Mithilfe der User_Id und der Passwortdaten können wir nun einen neuen Eintrag in DynamoDB erstellen.
Falls der Passwortname bereits in der Datenbank steht, wird das Passwort überschrieben.


GET Methode:

Die GET Methode liefert alle Passwörter eines Nutzers zurück.

Durch die User_Id können wir an DynamoDB eine Query schicken, welche uns alle Daten von einem einzigen Nutzer zurückliefert.
Dadurch wird sichergestellt, dass ein Nutzer nur auf seine eigenen Passwortdaten zugriff hat.

DELETE Methode:

Die DETELE Methode löscht ein Passwort eines Nutzers.

Auch für diese Methode existiert in API-Gateway ein JSON-Schema, welches den Body validiert.

Mithilfe des Authorizers und des Passwortnamens können wir nun für diesen Nutzer das Passwort löschen. Dafür müssen wir den Partitionsschlüssel (User_Id) und den Sortierschlüssel (PasswordName) angeben und diese Anfrage an DynamoDB senden.


Verschlüsselung

Um sicherzustellen, dass alle Passwörter sicher sind und nur von dem Nutzer gelesen werden können, welcher die Passwörter auch angelegt hat, nutzen wir lokale Verschlüsselung.
Damit der Nutzer die App auf mehreren Geräten gleichzeitig verwenden kann, muss es gemeinsamen Schlüssel geben.

Dieser Schlüssel basiert bei uns auf dem Login-Passwort. Dieser Schlüssel wird bei erfolgreichem Einloggen auf dem Gerät in einem sicheren Bereich gespeichert.

Bei iOS wird der “Keychain Service” und bei Android das “Android keystore system” genutzt. Das Login-Passwort wird zuvor zu einem Hash konvertiert.

Beim Ver- und Entschlüsseln wird ein AES Algorithmus verwendet. Die verschlüsselten Bytes müssen danach nur noch zu einem String encodiert werden, damit man das Passwort leichter zu einem JSON serialisieren kann.


Testing in Flutter

Um alle Funktionen in Flutter leicht testen zu können, haben wir uns für einen Integrationstest entschieden. Damit können wir herausfinden, ob alle wichtigen Funktionen richtig funktionieren. Unsere Hauptfunktionen, welche wir getestet haben sind:

  • Login eines Nutzers
  • Hinzufügen und Löschen eines Passworts
  • Ändern von Passwörtern
  • Ver- und Entschlüsselung
Die Login Prozedur prüft ob die App die richtigen Daten anzeigt, sobald der Nutzer eingeloggt wurde.


Terraform

Wir haben in unserem Projekt Terraform eingesetzt. In unser Ziel war es hierbei, das jeder einfach dieses Projekt bei sich zu Hause nachbilden kann. Dadurch war es aber auch möglich, schnell den AWS Account oder die Region zu ändern und sämtliche Infrastruktur Änderungen zu versionieren.

Main und Cognito

Grundsätzlich haben wir unseren Terraform Code in mehrere Files aufgeteilt. Dabei werden in der main.tf vor allem die Standard Terraform Parameter gesetzt und zusätzlich wird hier noch der Cognito Service aufgesetzt.

Variablen

Im variable.tf File werden für Terraform die AWS AccountID und die Region festgelegt. Diese Daten werden von Terraform benötigt, um die richtigen Account und Region für die Cloud Infrastruktur zu finden.

DynamoDB

Dienst und die Tabellen dem dynamodb.tf File werden, wie zu erwarten, alle DynamoDB Einstellungen übernommen. Hier wird also der AWS Dienst und die Tabellen Felder angelegt.

API Gateway

Im api.tf wird zunächst der normale AWS API Gateway Dienst eingestellt. Danach werden die Methoden der API definiert. Für jede Methode muss zudem angegeben werden welche Lambda Funktion ausgeführt werden soll, zusätzlich kann hier ein Template für die Request hinzugefügt werden. Dadurch wird unter anderem auch der Lambda Code vereinfacht. Jetzt wo in den Methoden alles Wichtige eingestellt ist, wird im tf File die Response erstellt.
Als Nächstes wird in Terraform definiert, wie die API bereitgestellt wird. Dadurch spart der Entwickler die Zeit später in AWS API Gateway den Deploy Butten von Hand zu drücken. Am Ende vom api.tf File wird noch für jede API Methode ein Model / Schema für die JSON Daten angeben. Das hat den Vorteil das Request an die API, ohne diese benötigten Daten, automatisch abgelehnt werden. Und zum Schluss wird noch der Authorizer von Cognito für die API richtig eingerichtet.


Lambda

Alle Lambda Funktionen müssen lokal gespeichert sein. Im lambda.tf File wird dann der Pfad zur Funktion definiert, beim Ausführen von Terraform wird dann ein zip File von jeder Funktion erstellt und in AWS Lambda hochgeladen.
Danach wird werden noch die Policies für das Logging mit Cloudwatch und die Access Rechte für DynamoDB geben.
Am Ende werden noch Permissions für API Gateway und Cognito an die richtigen Lambda Funktionen verteilt.

Probleme

Jedes Projekt hat seine Probleme, so auch unseres. Direkt am Anfang hatten wir viel mit AWS zu kämpfen, den wenn man für die Cloud entwickelt ist Debugging nicht mehr so einfach wie in einer IDE. Man kann dadurch kaum mehr nachvollziehen, was das AWS Setup oder der Lambda Code macht. Am Ende konnten wir das Problem über den Service Cloudwatch lösen. Hier werden alle Aktion geloggt, dadurch können Fehler schnell gefunden und gelöst werden.

Weitere Schwierigkeiten sind beim Arbeiten mit Terraform aufgetaucht. So sollte Terraform eigentlich von alleine alle Dienste in der richtigen Reihenfolge anlegen. Leider geht dies oft schief, und wir mussten im Terraform File von Hand mittels depens_on, die Reihenfolge einstellen. Ein weiteres Problem war, dass AWS beim Erstellen von Services viele Optionen im Hintergrund von alleine einstellt. Später mit Terraform raus zu finden, welche Einstellungen man jetzt genau braucht, war nur über das ausführliche Lesen der Dokumentation möglich.

Beim Arbeiten mit den AWS Dienst Cognito hatten wir Schwierigkeiten mit dem Bestätigen eines Nutzers. Denn Cognito legt zwar alleine alle Nutzer an, aber die Bestätigung des Accounts muss man von Hand gemacht werden. Jedoch konnten wir dieses Problem schnell über eine eigene Lambda Funktion lösen, welche automatisch jeden Nutzer verifiziert.

Erweiterungen

Das Projekt wurde von Anfang an mit dem Zeitlimit eines Semesters geplant. Jedoch könnte man mit weiterem zeitlichen Investment noch viele wichtige Features umsetzen:

  • So funktioniert Flutter auch im Web, leider haben wir innerhalb des Codes viele Abhängigkeiten zu iOS / Android. Jedoch wäre der Aufwand, die App auch als Web App laufen zu lassen, überschaubar.
  • Momentan sind die Passwörter in der Detailansicht noch sichtbar, in Zukunft sollte man diese verbergen und ein Kopierbutton hinzufügen. So könnte man die Passwörter noch besser schützen.
  • Zudem könnte man Power-Usern das Leben vereinfachen, in dem man eine Passwortsuche einbauen würde, so könnten Nutzer aus einem Berg von Passwörtern schnell das Richtige finden.
  • Ein weiter Feature wäre das Ändern des Masterpassworts, hier wäre aber der Aufwand sehr groß. Da jedes Passwort des Nutzers in der Datenbank mittels des Masterpassworts verschlüsselt ist, müsste jedes Passwort neu verschlüsselt werden.

Lessons Learned

Wie im Projekt bereits zu erkennen ist, haben wir viel Erfahrung mit den AWS Diensten: IAM, Cognito, Lambda, API Gateway, Cloudwatch und DynamoDB, sammeln können. Dank Terraform ist uns auch das Konzept der IaC (Infrastructure as Code) jetzt viel greifbarer geworden, zusätzlich hat uns Terraform fast schon gezwungen, von jedem benutztem AWS Service, die wichtigste Einstellung zu kennen. Außerdem konnten wir erste Kenntnisse in der App Entwicklung sammeln. Zuletzt haben wir unser Wissen im Bereich Testing um das Thema Integrations Tests erweitert.

Comments

Leave a Reply