So bringen Sie Ihre Benutzer dazu, sichere Kennwörter zu verwenden

Ich persönlich nutze für jedes Benutzerkonto ein eigenes Passwort. Der Passwort Manager meiner Wahl generiert mir automatisch sichere Kennwörter, das erleichtert es natürlich. Leider gehöre ich damit zu einer Minderheit, die allermeisten Internetnutzer haben ein einziges oder eine Handvoll Passwörter für sämtliche Accounts.

Damit die Kennwörter wenigstens sicher sind, haben viele Portale Regeln eingeführt. Beispielsweise, dass das Kennwort mindestens einen Grossbuchstaben, eine Zahl sowie ein Sonderzeichen enthalten muss. Möglicherweise sogar eine Mindestlänge von vier Zeichen. Aber das Problem ist, a$dF1 ist kein sicheres Kennwort, es lässt sich in wenigen Sekunden knacken.

Das Comic von XKCD bringt das Problem ziemlich gut auf den Punkt:

Wie bringe ich nun ein Benutzer dazu, für meine Webseite ein eigenes Kennwort zu verwenden, das auch noch sicher ist? Für meine letzte Webanwendung (AngularJS) habe ich ein kleines Script geschrieben, welches die Sicherheit des Kennwortes (Entropie) berechnet und grafisch darstellt.

Zusätzlich habe ich zwei Buttons, der erste Generiert ein neues Kennwort, der zweite wechselt zwischen der Klartext und der Kennwort Ansicht, bei der nur Sternchen angezeigt werden.
Sowohl für die Berechnung der Entropie als auch für die Generierung von neuen Kennwörtern nutze ich Drittkomponenten.

Berechnung der Kennwortsicherheit

Bei der Stärke von Kennwörtern spricht man von Entropie. Diese berechnet sich aus der Summe der Entropie der einzelnen Zeichen. Die Entropie eines einzelnen Zeichens hängt davon ab, welche Zeichen überhaupt verwendet werden. Sie berechnet sich aus der folgenden Formel.

H ist die Entropie des Kennwortes
L ist die Länge des Kennwortes
N ist die Anzahl möglicher Symbole

Eine Vierstellige PIN beim Smartphone, wenn nur Zahlen verwendet werden, hat dementsprechend die Entropie 13.29.

Dementsprechend hat das Kennwort asdf die Entropie 18.80, da die Länge des Kennwortes 4 Stellen ist und die Anzahl möglicher Zeichen 26. Das Alphabet hat ja 26 Buchstaben. Hätte ich Gross- und Kleinbuchstaben verwendet, wäre die Anzahl möglicher Zeichen 52. womit die Entropie 22.80 wäre.

Oft wird diese einfache Formel verwendet, um die Stärke eines Kennwortes zu bestimmen. Allerdings lässt diese Formel ausser acht, wie Hacker beim Knacken von Kennwörtern vorgehen. Für einen Hacker ist die Zeichenfolge asdf viel einfacher zu knacken, als Beispielsweise uqmc, obwohl die Entropie die gleiche ist. Der Grund ist, dass asdf eine Zeichenfolge ist, die so auf der Tastatur vorkommt und viele Menschen solche Abfolgen verwenden, um sich Kennwörter einfacher zu merken.

Winterthur ist kein sicheres Kennwort, genau so wenig wie Michael oder 19021986. Warum? Weil das alles Informationen sind, die ein Hacker über mich herausfinden kann. Mein Geburtsdatum findet man auf Facebook, Xing oder wo auch immer, meinen Wohnort im Telefonbuch. Die Entropie vom Kennwort MichaelWinterthur86 ist zwar 113.13 und damit sehr hoch, dennoch ist es einfach zu erraten.

Aus diesen Gründen berechne ich die Passwortstärke nicht selber, sondern verwende die Komponente Password Score von David Stutz. Diese Komponente enthält etliche Listen mit Kennwörtern, die bei der Berechnung berücksichtigt werden. Darunter Listen mit Städten, Vornamen und Nachnamen. Aber auch viele Passwortlisten, die zum Beispiel aus dem Adobe-Hack stammen. Zusätzlich erkennt die Komponente Leet speak Änderungen an Wörtern, Wiederholungen, Tastaturmuster sowie Daten.

Die Verwendung ist ein Zweizeiler.

var score = new Score(password);
var entropy = score.calculateEntropyScore();

Anschliessend verwende ich diesen Zahlenwert für die Anzeige eines Textes sowie zum Ändern der Farbe des Balkens.

if (entropy < 10) {
    $scope.pwStrengthDisplay = "Lächerlich";
    $scope.pwStrengthColor = "danger";
} else if (entropy < 20) {
    $scope.pwStrengthDisplay = "Sehr schwach";
    $scope.pwStrengthColor = "danger";
} else if (entropy < 30) {
    $scope.pwStrengthDisplay = "Schwach";
    $scope.pwStrengthColor = "warning";
} else if (entropy < 40) {
    $scope.pwStrengthDisplay = "Akzeptabel";
    $scope.pwStrengthColor = "warning";
} else if (entropy < 50) {
    $scope.pwStrengthDisplay = "Stark";
    $scope.pwStrengthColor = "success";
} else {
    $scope.pwStrengthDisplay = "Sehr stark";
    $scope.pwStrengthColor = "success";
}

Ich verwende das Bootstrap Layout, die Farbangabe danger steht also für Rot, warning für Gelb und success für Grün. Damit hat der Benutzer ein Visuelles Feedback, wie es um die Stärke des eingegebenen Passwortes steht.

Generierung von neuen Kennwörtern

Ich habe schon gehört, wie Benutzer beim Registrierungsvorgang klönten, "Oh nein, schon wieder ein Kennwort, welches nehme ich denn nun?". Daran soll es nicht scheitern, ich spendiere dem Kennwortfeld einen Button, der automatische Kennwörter generiert. Dazu verwende ich die Komponente password-generator von Bermi Ferrer.

Auch diese Komponente ist einfach in der Bedienung.

$scope.user.password = generatePassword(12, false);

Der erste Parameter ist die Länge des zu generierenden Kennwortes. Der zweite Parameter bestimmt, ob das Kennwort einfach zu merken sein soll. Da das Kennwortfeld das Kennwort normalerweise nicht als Text darstellt, sondern als runde Punkte, könnte der Benutzer das generierte Kennwort ja gar nicht lesen. Daher wechsle ich automatisch den Typ des HTML Elementes auf Text. Ein weiterer Button gibt dem Benutzer die Möglichkeit, zwischen den Typen Kennwort und Text hin und her zu wechseln.

Integration

Zusammenfassend hier der gesamte Quelltext.

$scope.$watch("user.password", function(newValue) {
    var score = new Score(newValue);
    var entropy = score.calculateEntropyScore();

    $scope.pwStrength = entropy;

    if (entropy < 10) {
        $scope.pwStrengthDisplay = "Lächerlich";
        $scope.pwStrengthColor = "danger";
    } else if (entropy < 20) {
        $scope.pwStrengthDisplay = "Sehr schwach";
        $scope.pwStrengthColor = "danger";
    } else if (entropy < 30) {
        $scope.pwStrengthDisplay = "Schwach";
        $scope.pwStrengthColor = "warning";
    } else if (entropy < 40) {
        $scope.pwStrengthDisplay = "Akzeptabel";
        $scope.pwStrengthColor = "warning";
    } else if (entropy < 50) {
        $scope.pwStrengthDisplay = "Stark";
        $scope.pwStrengthColor = "success";
    } else {
        $scope.pwStrengthDisplay = "Sehr stark";
        $scope.pwStrengthColor = "success";
    }
});

$scope.showOrHidePassword = function () {
    if (document.getElementById("password").type === "password") {
        document.getElementById("password").type = "text";
    } else {
        document.getElementById("password").type = "password";
    }
};

$scope.generatePassword = function () {
    document.getElementById("password").type = "text";
    $scope.user.password = generatePassword(12, false);
};

In HTML sieht das dann folgendermassen aus.

<div class="form-group">
    <label for="password">Neues Passwort</label>
    <div class="input-group">
        <input type="text" id="password" class="form-control" ng-model="newPassword">
        <div class="input-group-btn">
            <div class="btn-group" role="group">
                <button type="button" class="btn btn-default" ng-click="generatePassword()"><span class="glyphicon glyphicon-repeat"></span></button>
            </div>
            <div class="btn-group" role="group">
                <button type="button" class="btn btn-default" ng-click="showOrHidePassword()"><span class="glyphicon glyphicon-asterisk"></span></button>
            </div>
        </div>
    </div>
    <progressbar animate="false" value="pwStrength" type="{{pwStrengthColor}}"><b>{{pwStrengthDisplay}}</b></progressbar>
</div>

Das Kundenfeedback war sehr positiv, was zeigt, dass diese kleine Funktion einen grossen Mehrwert bietet. Wenn Benutzer damit nun sichere Kennwörter verwenden, hat sich der Aufwand definitiv gelohnt.