Doppelt genäht hält besser

Google Authenticator: so funktioniert die Zwei-Faktor-Authentifizierung
Kommentare

Die Kombination aus Benutzername und Passwort reichte lange aus, um einen Benutzer sicher zu identifizieren. Inzwischen gelangen diese Zugangsdaten immer öfter in falsche Hände. Also muss ein zusätzlicher Faktor die Authentifizierung absichern, wenn man wirklich auf Nummer sicher gehen will. Der Google Authenticator stellt einen solchen zweiten Faktor dar.

Es gibt viele Möglichkeiten, wie sich Cyberkriminelle die Zugangsdaten für Webanwendungen und alle möglichen anderen Zwecke beschaffen können. Auf der Clientseite kann zum Beispiel der Benutzer einem Phishingangriff zum Opfer fallen, oder Schadsoftware kann den Benutzernamen und das Passwort beim Einloggen ausspähen. Während der Übertragung kann ein Man-in-the-Middle die Zugangsdaten belauschen. Das ist ein vor allem bei unverschlüsselten Verbindungen und der Nutzung eines offenen WLANs nicht zu unterschätzendes Risiko. Und auf dem Server kann ein Cyberkrimineller zum Beispiel über eine SQL-Injection-Schwachstelle die Datenbank mit den Zugangsdaten abfragen oder nach einem erfolgreichen Eindringen als Datei kopieren. Beispiele für Passwortlecks auf der Serverseite gab es in den vergangenen Jahren reichlich. Ein Beispiel für auf dem Client ausgespähte Zugangsdaten ist der groß angelegte Identitätsdiebstahl, auf den das BSI im Januar aufmerksam gemacht hat. Die entdeckten E-Mail-Adressen und Passwörter wurden von Botnets gesammelt, also Spyware auf den Rechnern der Benutzer. Benutzername und Passwort allein reichen also nicht mehr aus, um einen Benutzer sicher zu identifizieren. Die Authentifizierung muss darum um einen weiteren Faktor ergänzt werden. Wobei an dieser Stelle ein wichtiger Hinweis nicht fehlen darf:

Auch zwei Faktoren schützen nicht vor einem Man-in-the-Middle

Eine Zwei-Faktor-Authentifizierung schützt nicht vor einem Man-in-the-Middle-Angriff: Da sich der Angreifer in der Verbindung zwischen Client und Server befindet, kann er sich nach erfolgreicher Authentifizierung durch den Benutzer gegenüber dem Server jederzeit als der betroffene Benutzer ausgeben (und gegenüber dem Benutzer als Server). Aber während der Man-in-the-Middle die belauschte Benutzername-Passwort-Kombination auch später noch jederzeit nutzen kann, um sich als der betroffene Benutzer auszugeben, ist das bei einer Zwei-Faktor-Authentifizierung nicht möglich. Denn der dafür zusätzlich benötigte zweite Faktor fehlt dem Angreifer.

Die Authentifizierungsmethoden im Überblick

Wie kann man prüfen, dass jemand der ist, der er zu sein vorgibt? Generell gibt es drei mögliche Methoden für die Authentifizierung eines Benutzers: Man kann ihn dran erkennen

1. was er weiß, also im klassischen Fall seinen Benutzernamen und das zugehörige Passwort oder die PIN beim Onlinebanking.
2. was er hat, zum Beispiel ein Token zum Erzeugen von Einmalpasswörtern oder eine Smartcard am Geldautomaten.
3. was er ist, zum Beispiel indem ein biometrisches Merkmal wie ein Fingerabdruck geprüft wird.

Alle drei Methoden haben jeweils Vor- und Nachteile, die sich durch die Kombination der Methoden teilweise aufheben lassen. Bei einer Zwei-Faktor-Authentifizierung ist meist der eine Faktor durch die bereits vorhandenen Zugangsdaten in Form von Benutzername und Passwort vorgegeben („Wissen“). Als zweiter Faktor kommen also „Besitz“ oder „Sein“ in Frage. Bewährt hat sich die Verwendung von „Besitz“ in Form eines „Geräts“ zum Erzeugen von Einmalpasswörtern. Das „Gerät“ kann entweder ein Smartphone mit einer App wie dem Google Authenticator oder ein spezielles Token sein. Die Zwei-Faktor-Authentifizierung besteht dann aus den beiden Faktoren

1. Wissen (von Benutzername und Passwort)
2. Besitz (des Tokens oder des Smartphones mit Google Authenticator zum Erzeugen der Einmalpasswörter)

Wie man mit Benutzername und Passwort sicher umgeht, setze ich als bekannt voraus. Wie Sie Passwörter (insbesondere mit PHP) sicher speichern, wird zum Beispiel hier beschrieben.

Wie hätten Sie das Passwort denn gerne?

Einmalpasswörter können zeitgesteuert, ereignisgesteuert oder im Rahmen eines Challenge-Response-Verfahrens erzeugt werden. Bei zeit- und ereignisgesteuerter Erzeugung berechnen Server und Client (egal, ob spezielle Hardware oder Smartphone-App) auf Grundlage eines gemeinsamen Startwerts mit den gleichen Verfahren ihre Einmalpasswörter. Der Server vergleicht dann den empfangenen Wert des Clients mit dem von ihm selbst berechneten Wert. Bei der zeitgesteuerten Erzeugung wird nicht nur der zur aktuellen Uhrzeit passende Wert akzeptiert, sondern auch die innerhalb eines gewissen Toleranzbereichs liegenden Werte (sofern sie nicht bereits verwendet wurden). Dadurch können eventuelle Abweichungen der Uhren von Client und Server ausgeglichen werden. Manche Verfahren können sich auch anhand der vom Client empfangenen Werte synchronisieren. Bei der ereignisgesteuerten Erzeugung werden die Einmalpasswörter auf Anforderung, zum Beispiel durch Drücken einer Taste auf dem Token, erzeugt. Das wirkt sich bei den Token positiv auf die Batterielaufzeit aus, da die Anzeige nur dann eingeschaltet werden muss, wenn sie benötigt wird. Auch ist nicht zwingend eine Uhr notwendig: Das neue Einmalpasswort kann ausgehend vom zuvor erzeugten generiert werden. Auch bei diesem Verfahren akzeptieren die Server im Allgemeinen mehrere mögliche Werte, sofern sie nicht bereits verwendet wurden. Es kann ja vorkommen, dass der Benutzer ein erzeugtes Einmalpasswort aus welchen Gründen auch immer nicht verwendet hat. Beim hier nicht interessierenden Challenge-Response-Verfahren stellt der Server eine Aufgabe (die Challenge), die der Client lösen muss (die Response). Ihr Vorteil ist, dass es keine Probleme mit der Synchronisation gibt.

Vor- und Nachteile von Token und App

Der größte Vorteil eines Tokens oder einer App als zweiten Faktor zur Authentifizierung ist, dass sie bei Bedarf ersetzt werden können. Bei biometrischen Merkmalen ist das nur in Grenzen oder auch gar nicht möglich. Dem stehen einige Nachteile gegenüber. Fangen wir mit der Server-/Betreiberseite an: Ein Token zum Erzeugen von Einmalpasswörtern muss angeschafft und verwaltet werden, was beides mit Kosten verbunden ist. Und irgendwann muss es ersetzt werden, was zusätzlichen Aufwand und Kosten erzeugt. Der Google Authenticator selbst kostet zwar nichts, seine Einbindung und Administration erzeugen jedoch ebenfalls Kosten. Ein Nachteil aus Sicherheitssicht ist die Möglichkeit, dass Benutzer das Token oder das Smartphone mit dem Google Authenticator weitergeben können. Außerdem kann es ihnen gestohlen werden. Auch für den Benutzer gibt es Nachteile. Er muss das Token mit sich führen, wenn er zum Beispiel eine darüber geschützte Webanwendung an mehr als einem Ort nutzen will. Ein Smartphone hat er zwar meistens dabei, aber nicht unbedingt immer.

Sowohl Token als auch Smartphone können gestohlen werden, wenn auch nicht wie im Fall von Passwörtern („Wissen“) unbemerkt vom Benutzer und aus der Ferne. Das Token oder Smartphone kann verloren gehen oder so beschädigt werden, dass es nicht mehr funktionsfähig ist. Im einfachsten Fall reicht es aus, wenn beim Token die nicht zu wechselnde Batterie leer ist. Was natürlich nach Murphys Gesetz immer im ungünstigsten Moment passiert. Genau so wie Smartphoneakkus gerne genau dann leer sind, wenn man das Smartphone gerade am dringendsten braucht. Und wenn es keine Möglichkeit zum Aufladen gibt.

Angriffe auf Token zum Erzeugen der Einmalpasswörter

Ein bekanntes Beispiel für ein Token zur Erzeugung von Einmalpasswörtern ist das SecurID-System von RSA Security. Das Token erzeugt alle sechzig Sekunden ein neues Einmalpasswort, das von der aktuellen Zeit und einem geheimen Startwert abhängig ist, und zeigt es auf einem Display an. Der Server kennt den Startwert ebenfalls und kann seinerseits daraus das jeweils gültige Token berechnen.

Das SecurID-System ist 2011 in Verruf geraten, RSA Security wurde das Opfer eines gezielten Angriffs in Form eines Advanced Persistant Threats. Die Angreifer verschafften sich nach der Kompromittierung eines Rechners nach und nach Zugriff auf immer weitere Systeme, bis sie ihr Ziel erreichten: einen Server, auf dem die Startwerte für die SecurID-Token gespeichert waren. Diese ausgespähten Startwerte erlauben es, die Zwei-Faktor-Authentifizierung zu umgehen, da damit unabhängig vom Token das passende Einmalpasswort berechnet werden kann. Und in der Tat wurden so danach weitere Unternehmen angegriffen. Eine Frage, die damals niemand schlüssig beantworten konnte: Warum hat RSA die Startwerte überhaupt gespeichert? Immerhin lässt sich damit der Schutz durch die SecurID-Token aufheben, sodass die Startwerte nur dem jeweiligen Kunden bekannt sein sollten (der sie ja für die Berechnung der Einmalpasswörter auf dem Server benötigt) und sonst niemanden. Inzwischen wurde bekannt, dass die NSA eine größere Summe an RSA Security gezahlt hat, damit dort ein unsicherer Zufallszahlengenerator als Default-Generator einer Krypto-Bibliothek verwendet wurde. Damit erscheint die Speicherung der Startwerte doch gleich in einem anderen Licht.

Abgesehen von diesem Fehlverhalten durch RSA sind solche Hardwaretoken sehr sicher, denn Schadsoftware hat keine Möglichkeit, sie zu kompromittieren. Es kann keine Software auf dem Token installiert werden, und die meisten Token haben auch keine Möglichkeit, sie mit einem Rechner oder Netzwerk zu verbinden. Das Problem ist ihr Preis: Schon das Token ist nicht gerade günstig, und bei der benötigten Serversoftware langen die Hersteller dann meist erst recht richtig zu. Sicherheit hat halt ihren Preis, was ja durchaus auch berechtigt ist. Nur muss der sich natürlich in einem vertretbaren Rahmen bewegen, und bei den Einmalpassworttoken ist der schnell überschritten. Ein Alternative zu speziellen Token sind entsprechende Apps für Smartphones – wie der Google Authenticator.

Angriffe auf Smartphone-Apps zum Erzeugen von Einmalpasswörtern

Sie haben es ja vielleicht schon gehört: Die von den Banken als Ersatz der TAN-Listen angepriesenen SMS-TANs sind bereits unsicher. Die Cyberkriminellen haben einfach ihre Onlinebankingtrojaner um Mobilversionen erweitert, um die SMS-TANs abzufangen. Und auch „normale“ Spyware für Smartphones sammelt quasi routinemäßig SMS, frei nach dem Motto „Vielleicht kann man ja was damit anfangen“. Bisher gibt es zwar keine Schadsoftware, die Einmalpasswort-Apps angreift, aber die wird es sicher irgendwann geben. Im Fall von iOS verhindert die Sandbox ein einfaches Ausspähen, unter Android dürfte ein Angriff aber deutlich leichter möglich sein. Aber bis es soweit ist, sind der Google Authenticator und seine „Kollegen“ eine gute Möglichkeit, die Authentifizierung um einen zweiten Faktor zu erweitern. Und selbst wenn es irgendwann Schadsoftware gibt, die diese Apps angreift, werden die Angriffe sich sicher erst mal auf große Anbieter, im Fall des Google Authenticator natürlich vor allem Google, konzentrieren. Dann ist immer noch Zeit, auf ein sicheres, aber dafür teures Token als zweiten Faktor auszuweichen. Wenn man denn einen Tokenhersteller findet, dem man vertraut.

Der Google Authenticator im Überblick

Den Google Authenticator gibt es von Google als App für Android, iOS und BlackBerry, außerdem steht für den Server ein PAM-Modul zur Verfügung. Von Drittherstellern gibt es viele weitere Implementierungen. Mal abgesehen davon, dass der Google Authenticator vom chronischen Datensammler Google stammt, gibt es nichts daran auszusetzen. Denn im Gegensatz zum proprietären Protokoll der SecurID-Token setzt der Google Authenticator auf offene Standards und ist damit zu allen entsprechenden Implementierungen kompatibel. Implementiert sind die Algorithmen HMAC-Based One-Time Password (HOTP, RFC 4226) und Time-Based One-Time Password (TOTP, RFC 6238).  Im Gegensatz zu RSA kennt Google auch nicht die Startwerte (sofern man nicht den Fehler macht, sie Google selbst mitzuteilen): Ein Server, der den Google Authenticator als zweiten Faktor für die Authentifizierung verwenden will, erzeugt für jeden Benutzer einen geheimen Startwert (den Seed), der auf das Gerät des Benutzers übertragen wird. Dazu kann ein QR-Code verwendet werden, der sich zum Beispiel auf Googles Website erzeugen lässt. Was man natürlich tunlichst unterlassen sollte, denn der Startwert muss ja geheim bleiben. Entweder man erzeugt den QR-Code lokal oder der Benutzer muss den Seed abtippen. Sowohl App als auch Server erzeugen aus dem Seed und aus der aktuellen Zeit oder einem Zähler dann die Einmalpasswörter.

Ein Schwachpunkt: Der Seed

Auf dem Server muss also für jeden Benutzer außer Benutzername und Passwort auch der Seed gespeichert werden. Und das muss sicher geschehen, denn wer den Seed kennt, kann damit seinen eigenen Google Authenticator entsprechend konfigurieren und sich als Benutzer anmelden. Das Passwort kann als Hash-Wert sicher gespeichert werden, dafür gibt es sogar spezielle Hash-Funktionen. Für den Seed steht diese Möglichkeit nicht zur Verfügung, da er für die Berechnung der Einmalpasswörter als Klartext benötigt wird. Sicherheitshalber sollte er in der Datenbank trotzdem verschlüsselt gespeichert werden, sodass ein Angreifer über einen SQL-Injection-Angriff nur den verschlüsselten Seed-Wert ausspähen kann. Im Fall einer Kompromittierung des Servers bietet diese Verschlüsselung aber keinen Schutz, da der zum Entschlüsseln nötige Schlüssel ja ebenfalls auf dem Server gespeichert werden muss, um die Seeds zum Berechnen der Einmalpasswörter zu entschlüsseln.

Google Authenticator unter der Haube

Für die Berechnung der Einmalpasswörter werden zwei Eingaben verwendet: Der vom Server für jeden Benutzer erzeugte individuelle Startwert von 80 Bit Länge und entweder die Anzahl der 30-Sekunden-Perioden seit Start der Unix-Zeit oder ein bei jedem Aufruf hochgezählter Zähler. Der Startwert wird vom Server als sechzehn Zeichen langer Base32-kodierter String gespeichert und kann entweder als dieser String oder als QR-Code auf das Smartphone übertragen werden. Das Einmalpasswort wird sowohl vom Google Authenticator als auch vom Server nach dem Pseudocode in Listing 1 erzeugt.

function GoogleAuthenticatorCode($seed) {
  // Schlüssel für HMAC-SHA1 dekodieren
  $schluessel := base32decode($seed);

  // "Nachricht" für den HMAC-SHA1
  $nachricht  := floor(aktuelle Unix-Zeit / 30);

  // Hash-Wert der "Nachricht" mit HMAC-SHA1 mit Seed als Schlüssel berechnen
  $hash := HMAC-SHA1($schluessel, $nachricht);

  // Das letzte Nibble dient als Offset
  $offset := [Letztes Nibble von $hash];

  // Wir brauchen nur noch 4 Bytes ab dem $offset
  $gekuerzterHash := $hash[$offset..$offset+3];

  // erstes Bit ("most significant bit") auf Null setzen,
  // verhindert Verwirrungen bzgl. signed/unsigned Modulo-Operationen
  $gekuerzterHash := [$gekuerzterHash mit 1. Bit = 0];

  // Einmalpasswort ist $gekuerzterHash mod 1.000.000 (10 ^ Passwortlänge)...
  $code := $gekuerzterHash mod 1000000;

  // ... mit 0 aufgefüllt auf Länge 6
  $code := pad($code, 6, '0');

  // fertig, Einmalpasswort kann zurückgegeben werden
  return $code ;
}

Als kryptografische Funktion wird der Hash-based Message Authentication Code (HMAC) auf Basis der Hash-Funktion SHA1 verwendet, HMAC-SHA1. Der dient eigentlich dazu, einen von einem geheimen Schlüssel abhängigen Prüfwert (Message Authentication Code) einer Nachricht zu berechnen: MAC = HMAC-SHA1(Schlüssel, Nachricht). Als Schüssel wird der Startwert verwendet, als „Nachricht“ der zweite Parameter. Bei einem zeitbasierten Einmalpasswort ist das die Anzahl der 30-Sekunden-Perioden seit Start der Unix-Zeit. Das Einmalpasswort ist ein Teil der Ausgabe von HMAC-SHA1(„Startwert“, „30-Sekunden-Perioden seit Start der Unix-Zeit“). Statt der Uhrzeit kann auch ein bei jedem Aufruf hochgezählter Zähler als „Nachricht“ verwendet werden. Dafür müsste der Zähler zusammen mit dem Startwert an GoogleAuthenticatorCode() übergeben werden. Der Code in Listing 1 würde also nur in der ersten und sechsten Zeile geändert:

Zeile 1: function GoogleAuthenticatorCode($seed, $zaehler) {
Zeile 6:   $nachricht  := in 8 Bytes kodierter $zaehler

Falls Sie bei der Erwähnung von SHA1 stutzen sollten: Eigentlich sollte man die Hash-Funktion SHA1 nicht mehr verwenden, da sie zumindest theoretisch angreifbar ist. Das betrifft aber nur den Einsatz als Hash-Funktion, da sich Kollisionen berechnen lassen. Es hat aber keine Auswirkung auf die Berechnung des Message Authentication Codes durch den HMAC, der SHA1 intern verwendet. Und noch weniger auf die Berechnung der Einmalpasswörter, die HMAC-SHA1 intern verwendet.

Die Serverseite, am Beispiel von PHP

Es gibt verschiedene Implementierungen zur Nutzung des Google Authenticator mit PHP-Anwendungen. Als Beispiel verwende ich die von Michael Kliewe. Die Nutzung ist äußerst einfach (Listing 2, nach diesem Beispiel). Auf eine weitere Beschreibung verzichte ich, besser als die von Michael Kliewe könnte sie sowieso nicht werden. Ich persönlich würde den QR-Code nicht von Google erzeugen lassen. Allerdings mehr aus Prinzipgründen als aufgrund tatsächlicher Befürchtungen: Der Seed ist das gemeinsame Geheimnis von Client und Server und geht keinen Dritten etwas an. Aber selbst wenn Google (oder auch jeder andere Drittanbieter zum Erzeugen von QR-Codes) die übertragenen Daten speichert, kann man dort nichts damit anfangen, solange nicht bekannt ist, zu welchem Benutzer(-namen) und Passwort der Seed gehört. Gefährlicher ist es, wenn ein Man-in-the-Middle die Kommunikation zwischen Client und Server während der Initialisierung belauscht. Der kann dann nicht nur Benutzername und Passwort sondern auch den Seed ausspähen. Der Seed darf also nur über eine verschlüsselte Verbindung übertragen werden, und wenn es besonders sicher sein soll, bietet sich eine „Out-of-Band“-Übertragung in Form eines Briefs an.

<?php

require_once '../PHPGangsta/GoogleAuthenticator.php';

$ga = new PHPGangsta_GoogleAuthenticator();

// Startwert erzeugen
$seed = $ga->createSecret();
echo "Startwert ist: ".$seed."\n\n";

// URL zum Erzeugen des QR-Codes (besser nicht verwenden, siehe Text)
$qrCodeUrl = $ga->getQRCodeGoogleUrl('Blog', $secret);
echo "Google Charts URL für den QR-Code: ".$qrCodeUrl."\n\n";

// Prüfen eines Einmalpassworts
// 1. Aktuelles Einmalpasswort erzeugen - normalerweise käme das vom Client
$aktuellesPasswort = $ga->getCode($secret);
echo "Prüfe Einmal-Passwort '$aktuellesPasswort' und Startwert '$seed':\n";

// 2. Die eigentliche Prüfung:
$ergebnis = $ga->verifyCode($seed, $aktuellesPasswort, 2);    // 2 = 2*30 Sek. Zeittoleranz
if ($ergebnis) {
  echo 'OK!';
  // Nicht vergessen: Akzeptierte Einmalpasswörter müssen so lange gespeichert
  // werden, wie sie gültig sind. In diesem Zeitraum dürfen sie nicht erneut
  // akzeptiert werden, um Replay-Angriffe zu verhindern
} else {
  echo 'Fehler!';
}

Fazit

An einem zweiten Faktor für die Authentifizierung führt früher oder später kein Weg vorbei. Die Token zum Erzeugen von Einmalpasswörtern sind sicher (wenn der Hersteller nicht falsch spielt), aber teuer. Die Smartphone-Apps sind eine gute Alternative, so lange es noch keine spezielle Schadsoftware gibt, die sie angreift. Warum sollte man also nicht zum Google Authenticator greifen? Immerhin ist der sogar Open Source und man kann ziemlich sicher sein, dass keine Hintertür enthalten ist. Und falls Sie Googles Implementierung für Android misstrauen, weil die nach Version 2.21 wegen enthaltener „Google-specific workflows“ nicht mehr Open Source ist, gibt es freie Alternativen. Zum Beispiel die Forks OTP Authenticator von Kai Engert und FreeOTP von Red Hat.

Auch die Zwei-Faktor-Authentifizierung hat aber eine Schwachstelle: Was ist, wenn der zweite Faktor ausfällt, zum Beispiel weil das Smartphone kaputt ist, verloren oder gar gestohlen wurde? Bei einer Zwei-Faktor-Authentifizierung muss es immer eine Möglichkeit geben, sich auch ohne zweiten Faktor zu authentifizieren. Und dieser Weg muss so sicher sein, dass er nur dem tatsächlichen Benutzer offen steht und nicht von einem Cyberkriminellen genutzt werden kann, um sich mit der Ausrede „Mein Smartphone ist kaputt, bitte lasst mich rein“ Zugriff auf die Webanwendung zu verschaffen. Wie man diesen „Noteingang“ sicher implementiert, ist eine größere Herausforderung als die Nutzung des Google Authenticator und kann nur im Kontext der jeweiligen Anwendung gelöst werden. Der bekannte Ansatz einer Sicherheitsfrage (dann aber bitte mit vom Benutzer frei wählbarer Frage und Antwort und nicht mit Fragen, die jeder Trottel nach etwas Recherche in Social Networks beantworten kann) kann ausreichend sein, meist ist aber ein bisschen mehr Aufwand nötig.

Aufmacherbild: Knitting in the Round on Double Pointed Needles von Shutterstock / Urheberrecht: Melica

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -