Nachdem ihr im vorherigen Blogbeitrag über die API hinter dem Projekt „Smart Lock“ gehört habt, wollen wir in diesem Beitrag das Sicherheitskonzept von „Smart Lock“ erläutern. Gerade bei einer intelligenten Türsteuerung ist es wichtig, dass alle gängigen Sicherheitsfeatures eingehalten werden. Dieser Prozess beginnt bei uns bereits auf der Hardwareseite und erstreckt sich über alle Aspekte des Endgeräts.

1. Sicheres Hashing aller Passwörter

Innerhalb der Benutzeroberfläche können sich Administratoren einloggen und ihre Zugangsdaten verwalten. Wurde ein Passwort geändert, sendet die Benutzeroberfläche eine Anfrage an die Web-API der Anwendung. Hier wird das Passwort mit dem bcrypt-Verfahren gehasht und anschließend in der Datenbank gespeichert.

Wir verwenden bcrypt, da es von Sicherheitsforschern empfohlen wird. Betrachtet man die Historie der Hashing-Verfahren erkennt man, dass die empfohlenen Verfahren häufig wechseln. Dies ist auf die stetig steigende Rechenkapazität der Endgeräte zurückzuführen (Moore’s Law). Ältere Verfahren wie etwa MD5 oder SHA1 (bzw. SHA256 oder SHA512) sind demnach überholt. Der zugrundeliegende Algorithmus dieser Verfahren kann immer schneller ausgeführt werden, wodurch Brute-Force-Angriffe einfacher möglich sind. Hingegen verfolgt Bcrypt das Ziel deutlich rechenintensiver als zuvor bekannte Hashing-Verfahren zu sein. Die Berechnung eines Hashs wird somit erschwert, was aber bei einer normalen Nutzung des Algorithmus nicht ins Gewicht fällt. Gleichzeitig werden Brute-Force-Angriffe stark verlangsamt.

Schema eines brypt Hashes Quelle: CC BY-SA 3.0 Andrei Herford

Außerdem ist das sogenannte „salting“ der Passwörter zu beachten. Jedem Nutzer wird hierbei ein zufallsgenerierter Token zugewiesen. Dieser wird bei jedem Login an das Passwort angehängt wird. Aus dem Passwort „1234“ würde dadurch zum Beispiel das Passwort „1234d3RM*qA@9W“ werden. Anschließend wird das neue Passwort gehasht und wie ein normales Passwort behandelt. Dieses Verfahren wird hauptsächlich angewendet, um die Nutzung sogenannter Rainbow Tables zu unterbinden. Eine Rainbow Table ähnelt einem Wörterbuch. Jedem Hash wird sein ursprünglicher Wert zugeordnet, wodurch ein Angreifer das eigentliche Passwort bestimmen kann.

 

Laut Moore’s Law verdoppelt sich die Rechenkapazität alle 12 bis 24 Monate
Quelle: CC BY-SA 3.0 Wgsimon

2. Eindeutige Identifikation der Nutzer durch Sessions

Wie ihr schon im vorherigen Post gesehen habt, stellt die API eine Methode bereit, mit der sich Nutzer in der Anwendung anmelden können. Innerhalb dieser Funktion wird das eingegebene Passwort gehasht. Im Anschluss wird der generierte Hash-Wert mit dem hinterlegten Hash-Wert der Datenbank verglichen. Stimmen beide überein, wird der Zugriff auf die Anwendung gewährt und eine verschlüsselte serverseitige Session erstellt. Diese enthält dann alle Informationen des angemeldeten Admins. Anhand dieser Session kann in jedem weiteren API-Aufruf die Identität des Nutzers gewährleistet werden und eine unerlaubte Nutzung der API verhindert werden. Weiterhin kann die serverseitige Session nicht durch den Admin manipuliert werden, was bei einer clientseitigen Sessions durchaus möglich wäre.

Wählt der Nutzer den Logout in der Weboberfläche aus, wird seine Session im Backend zerstört. Nach einer längeren Inaktivität läuft die Session aus und der Nutzer wird automatisch ausgeloggt.

Die Sessions werden durch eine methodenübergreifende Middleware verwaltet.

3. Verifikation aller API-Anfragen

Die Middleware wird weiterhin verwendet, um alle API-Endpoints abzusichern. Die Middleware prüft bei jedem einzelnen Aufruf, ob eine valide Session besteht. Ist dies nicht der Fall, wird der Statuscode HTTP 401 zurückgegeben. Durch diesen Mechanismus können wir sicherstellen, dass die API nicht missbraucht wird.

4. Korrekte Berechtigungstrennung unter Linux

Die korrekte Trennung der Berechtigungen unter Linux ist wichtiger als alle bisher erläuterten Sicherheitsmaßnahmen. Diese besagt, dass Node.js niemals mit Root-Rechten ausgeführt werden darf. So kann sichergestellt werden, dass eventuelle Fehler in der API nicht zum Erlangen von Superuser-Rechten missbraucht werden. Idealerweise wird die fertige Anwendung niemals Root-Rechte anfordern müssen, um nicht die Integrität der Firmware zu gefährden. Denn mit Superuser-Rechten können alle Bestandteile der Firmware eingesehen und geändert werden.

Ich hoffe, dass ihr ein paar interessante Einblicke in unser Sicherheitskonzept erlangen konntet. Weißt uns gerne in den Kommentaren auf eventuelle Unstimmigkeiten hin :).

SmartLock (4): Sicherheit geht vor