OTP-Codes per SMS sind eine billige Lösung für eine 2-Faktor Authentifizierung. Mit einem Raspberry Pi und einem GSM Board kann der Raspberry Pi SMS Nachrichten empfangen und auf einem Dashboard im Netz anzeigen. Mit sideos SSI Login werden die Codes für verschiedene User in einem Team verfügbar gemacht, so dass jeder nur die für ihn/sie relevanten Codes sehen kann.

Die Idee

One-Time-Passwörter kamen im 2. Weltkrieg in Mode und wurden dann immer wieder mal neu aufgelegt. Als TAN-Listen, als ChipTan Generator und irgendwann als App-Token. Aktuell gibt es eine wachsende Zahl an Anwendungen, die auf eine SMS OTP setzen. Es ist schon erstaunlich, dass sie sich bis 2023 halten konnten. Der Vorteil ist, dass sie für den Anwendungsbetreiber relativ günstig sind. Relativ, weil für eine Bank die Kosten für die SMS in der Größenordnung vom Preis einer Überweisung liegen. Besonders benutzerfreundlich sind sie zudem bis heute nicht. Außerdem braucht der Benutzer Mobilfunkempfang damit die SMS überhaupt im richtigen Moment ankommt. Und da es ein einfacher Text Code ist, ist völlig unklar ob er vom richtigen Sender kommt (5 der Dienste die ich nutze, geben alle den gleichen Absender AUTHMSG an), und man fragt lieber nicht, wie der OTP Code vom Handy in das richtige Formular kommt.

Die Idee ist nun, die SMS OTPs vom Handy in einen Webdienst zu bekommen. Damit wird die SMS vom Mobilfunk ins Netz geholt und kann von belieber Stelle über das Internet abgeholt werden. In einem Team ermöglicht dieser SMS Hub dann auch die Verteilung der OTP an einen Vertreter, man kann die Zustellung von Firmencodes an private Handys vermeiden, oder man kann OTP Codes an Teamkollegen zustellen, die gar kein Handy haben sollen oder gar nicht nutzen können.

Was man dann noch machen kann, ist eine Benutzerverwaltung oben drauf zu bauen. Einer darf die OTPs von Anwendung A, B und C sehen, ein anderer nur die Anwendung B und D. Vertretungen und andere Rollen einrichten klappt dann unabhängig von umständlichen Eintragen neuer Handynummern bei den Anwendungsanbietern.

Und damit man jetzt nicht eine SMS OTP mit Benutzername und Passwort wieder komplett unsicher macht, nutzen wir hier eine SSI-Wallet zum Einloggen in den Webdienst. Eine SSI-Wallet gibt es von sideos als App oder als Browser-Extension. Wie das Einloggen mit einer SSI-Wallet in einen Webdienst eingebaut werden kann, habe ich im letzten Artikel Webserver Login ohne Passwort gezeigt.

Disclaimer

SMS OTPs sind Authentifizierungscodes und sollen die Sicherheit erhöhen. An dieser Stelle hier skizziere ich nur das Konzept. Um es ausreichend sicher zu machen, muss der Webdienst und der RasPi vernünftig abgesichert werden. Für einen Einsatz in sicherheitsrelevanten Anwendungen ist also noch etwas Feinschliff notwendig. Also noch mal deutlich: Hier wird nur die Idee beschrieben, bitte nicht in wichtigen Anwendungen genauso nachmachen, für irgendwelche Schäden schließe ich jede Haftung aus.

Die Hardware

Ich habe für den Test einen Raspberry Pi 3A genommen. Der ist kompakt, hat einen GPIO Anschluss, der sich allerdings etwas zu nah am USB Port befindet.

Für den SMS Empfang habe ich mir ein Waveshare SIM868 GSM/GPRS HAT besorgt. Es kostet ca. 32 Euro auf Amazon und kann SMS Nachrichten empfangen, aber auch Telefonieren, Bluetooth Verbindungen herstellen, hat einen Micro USB Port und einen Anschluss für den GPIO Port des RasPi.

Das Modul hat einen Kartenhalter für eine SIM Karte in Standardgröße. Die muss man natürlich haben und aktivieren. Das Modul wird dann einfach auf den GPIO Port des Raspberrys gesteckt und ist dann sofort betriebsbereit. Anschalten per Druck auf den PWR Button für mindestens 1s nicht vergessen. Schaut aber im Handbuch nach, wie man das SMS Gateway einrichtet, denn bei einer neuen SIM Karte kann es möglicherweise noch nicht konfiguriert sein.

Jetzt noch ein Raspberry Pi OS auf den RasPi installieren, Wifi einrichten und es kann losgehen.

Das Dashboard

Das Dashboard ist eine Node.js Anwendung und basiert auf dem Code des letzten Artikels Webserver Login ohne Passwort. NodeJS und yarn sollten also installiert sein. Für die Anmeldung wird die sideos Wallet benötigt. Woher man die bekommt und wie man die Zugangsdaten einrichtet, wird im Artikel erklärt.

Der Code für die Anwendung ist auf Github erhältlich und besteht aus dem Dashboard und dem SMS Empfänger. Mit dem folgenden Aufruf wird der Quellcode heruntergeladen.

git clone git@github.com:rheikvaneyck/team-auth.git

Anschließend installiert man die Node Pakete, richtet die Umgebungsvariablen wie im Artikel Webserver Login ohne Passwort beschrieben ein und startet den Server mit

cd team-auth
yarn install
yarn start:dev

Login

Auf der Login Page wird der QR Code zum Einloggen angezeigt und bei erfolgreicher Präsentation des erforderlichen Credentials erhält der Benutzer Zugriff auf das Dashboard. Neu ist nun auch die Unterstützung der SSI Desktop Wallet. Die gibt es Browser Extension im Chrome Store, dazu aber in einem späteren Artikel mehr.

Nach dem Einloggen schaut der Service nach, ob eine OTP für den Benutzer vorliegt und listet alle gültigen OTPs für den Benutzer auf. Der Benutzer kann nun den benötigten Code aus der Liste kopieren oder abtippen. Alle 10 Sekunden wird geschaut, ob ein neuer Code vorliegt.

Was die Anwendung macht, ist Folgendes:

  1. Sie schaut im SSI Credential (dem digitalen Ausweis aus dem SSI Wallet des Benutzers) das beim Einloggen vorgewiesen wird, nach dem Namen des Benutzers.
  2. Falls für den Namen Apps eingerichtet sind, wird anhand der Liste aller Apps geprüft, ob eine SMS OTP für den Benutzer vorliegt.
  3. Falls ein OTP gefunden wird, wird dieses in die Liste der aktuellen OTPs eingefügt.
  4. Wenn ein OTP ungültig wird, wird es wieder von der Liste gelöscht.
user found: Marcus
apps: SendGrid,Amazon,paypal,test
[ 'SendGrid', 'Amazon', 'paypal', 'test' ]
test otp for Marcus : WUJDBD
returned: {"did":"did:key:v001:z6Mkn3hVeAghBPWgM8PHLLWYkQoRbFptGECKkRpdFz36x23V","name":"Marcus","issuer":"MN Strategy Consult"}

SSI Credentials

Die Anmeldung mit einem SSI Credential ist deswegen so genial, weil nicht nur der Benutzer mit Hilfe seiner geheimen Schlüssel in der Wallet beweisen muss, dass er der richtige ist, sondern weil die Credentials auch von einem Dritten unterschrieben wurden. Hier im Beispiel ist es der Issuer MN Strategy Consult. Die Information kann man zusätzlich nutzen, um den Benutzer einer Organisation oder einem Team zuzuordnen.

Der SMS Empfänger

Der SMS Empfänger auf Basis des Waveshare SIM868 GSM/GPRS HAT wird einfach per serieller Schnittstelle angesprochen. Dazu wird die Serielle Schnittstelle im RasPi mit Hilfe von raspi-config aktiviert. Im Menüpunkt 3 Interface Options wird unter I6 Serial Port die Serielle Schnittstelle eingerichtet. Die erste Frage nach der Aktivierung der Shell wird verneint, die zweite Frage nach dem Hardware Port wird bejaht. Anschließend steht nach einem Neustart die serielle Schnittstelle unter /dev/ttyS0 zur Verfügung.

Mit einem Terminal Programm für die serielle Schnittstelle kann man die Schnittstelle erst einmal ausprobieren. Die Eingabe von AT + Enter sollte ein OK zurückgeben.

Die Folgenden Kommandos richten die SMS Darstellung als Textformat ein und rufen alle SMS Nachrichten ab:

AT+CMGL="REC READ"
+CMGL: 1,"REC READ","+491123456789","","23/04/06,14:13:34+08"
WUJDBD
OK

Wenn das funktioniert, sollte auch das SMS Empfänger Programm funktionieren. Das Programm befindet sich im Unterverzeichnis poll-sms/ und ist eine NodeJS Anwendung. Sie wird also genauso wie der Webserver installiert und gestartet:

cd poll-sms
yarn install
yarn start

Redis

Die Daten werden temporär in Redis gespeichert. Redis ist eine schnelle Datenbank für Key/Value Tabellen und damit genau das richtige für session Daten und die OTP Nachrichten. Auf dem RasPi wird Redis mit dem folgenden Kommando installiert:

sudo apt update && sudo apt install redis

Auch wieder ein Disclaimer: Für die Sicherheit von Redis muss man selbst sorgen. Hier wird nur die Idee gezeigt. Die Abschottung des RasPi mit einer Firewall, die Einrichtung der Authentifizierung für Redis und die Härtung des System ist nicht Gegenstand des Artikels.

Die Konfiguration

Welcher Benutzer welche OTPs erhalten soll und welche Absender IDs die Anwendungen haben wird in einer Konfigurationsdatei default.json im Verzeichnung config/ hinterlegt. Die Datei enthält zum Beispiel folgende Daten:

{
  "users": {
      "Marcus": "SendGrid,Amazon,paypal,test"
  },
  "app_senders": {
      "test": "+49123456789",
      "paypal": "7272",
      "SendGrid": "AUTHMSG",
      "Grover": "AUTHMSG",
      "Coinsbase": "AUTHMSG",
      "Mailchimp": "AUTHMSG",
      "OpenAI": "AUTHMSG"
  }
}

Jeder Benutzer hat also eine durch Kommas separierte Liste an Anwendungen, und jeder dieser Anwendungen hat eine Absende-ID, anhand dessen die OTPs zugeordnet werden. Und hier sieht man eine kleine Herausforderung:

Manche Anwendungen nutzen die selben Absender-ID AUTHMSG. Hier muss man die richtige Anwendung aus den SMS Nachrichten selbst raussuchen und zuordnen. Schwer ist das nicht, mir ist es aber ein Rätsel, wie manche Provider so bedenkenlos die Codes mit einem quasi anonymen Absender rausschicken und damit Social Engineering noch einfacher machen.

Fazit

Zum einen kann man sehen, wie Kacke SMS OTPs eigentlich sind und wie unpraktisch sie im realen Alltag erscheinen. Offenbar ist es manchen Providern eher Banane, ob 2FA wirklich die Sicherheit erhöhen soll oder einfach nur auf den Best Practice Zug gesprungen wird. Mit einem SMS OTP Hub könnte man die Situation in manchen Anwendungen etwas verbessern. Aber wenn ich ehrlich bin, würde ich den Providern empfehlen, dringend direkt auf SSI Anmeldungen zu wechseln und auch einmal über die tatsächlichen Nutzerbedürfnisse nachzudenken.