Inhaltsverzeichnis

  • Hashes und Zweifaktorauthentifizierung

    • Einsatz beim Speichern von Passwörtern

    • Zwei-Faktor-Authentifizierung


Hashes und Zweifaktorauthentifizierung

== Hashes und Zweifaktorauthentifizierung

Immer wieder liest man in den Nachrichten, dass eine Datenbank geknackt wurde und somit alle Benutzernamen mit Passwörtern entwendet wurden. Häufig wird eine Kombination aus Benutzername und Passwort von einem Benutzer bei unterschiedlichen Diensten genutzt, so dass die Kenntnis dieser zum Missbrauch verschiedenster Dienst führen könnte.

Somit ist die minimale Sicherheitsidee die, dass Passwörter nicht im Klartext gespeichert werden. Für diesen Zweck bieten sich Hash-Funktionen an, die zu jedem Eingangstext einen Ausgabewert (Hash-Wert) mit fester Länge (also beispielsweise genau 256 Bit) erstellen, wobei es nahezu unmöglich sein soll , unter der Kenntnis eines solchen Hash-Wertes den ursprünglichen Eingangstext zu rekonstruieren (bedeutet: die Rechenzeit dafür soll so groß sein, dass es quasi unmöglich ist).

Es kann vorkommen, dass unterschiedliche Eingangstexte zu gleichen Hashes führen (sogenannte Kollisionen), wobei die Wahrscheinlichkeit dafür möglichst klein sein soll.

Wichtig ist, dass identische Eingangstexte immer zu identischen Hash-Werten führen.

Es gibt unterschiedliche Algorithmen, solche Hash-Werte zu berechnen. So wären da die Algorithmen MD5, SHA-1 und SHA-256, die man auf der Seite http://www.xorbin.com/tools/sha256-hash-calculator ausprobieren kann.

Je nach Einsatzgebiet ist mal der eine, mal der andere Algorithmus besser geeignet. So wird MD5 häufig verwendet, um die Integrität von Daten zu überprüfen, also beispielsweise, ob eine Datei richtig heruntergeladen wurde.

Hier einige Beispiele für Hash-Werte:

Immer wieder liest man in den Nachrichten, dass eine Datenbank geknackt wurde und somit alle Benutzernamen mit Passwörtern entwendet wurden. Häufig wird eine Kombination aus Benutzername und Passwort von einem Benutzer bei unterschiedlichen Diensten genutzt, so dass die Kenntnis dieser zum Missbrauch verschiedenster Dienst führen könnte. Somit ist die minimale Sicherheitsidee die, dass Passwörter nicht im Klartext gespeichert werden. Für diesen Zweck bieten sich _Hash-Funktionen_ an, die zu jedem Eingangstext einen Ausgabewert (_Hash-Wert_) mit fester Länge (also beispielsweise genau 256 Bit) erstellen, wobei es nahezu unmöglich sein soll , unter der Kenntnis eines solchen Hash-Wertes den ursprünglichen Eingangstext zu rekonstruieren (bedeutet: die Rechenzeit dafür soll so groß sein, dass es quasi unmöglich ist). Es kann vorkommen, dass unterschiedliche Eingangstexte zu gleichen Hashes führen (sogenannte _Kollisionen_), wobei die Wahrscheinlichkeit dafür möglichst klein sein soll. Wichtig ist, dass identische Eingangstexte immer zu identischen Hash-Werten führen. Es gibt unterschiedliche Algorithmen, solche Hash-Werte zu berechnen. So wären da die Algorithmen MD5, SHA-1 und SHA-256, die man auf der Seite http://www.xorbin.com/tools/sha256-hash-calculator ausprobieren kann. Je nach Einsatzgebiet ist mal der eine, mal der andere Algorithmus besser geeignet. So wird MD5 häufig verwendet, um die Integrität von Daten zu überprüfen, also beispielsweise, ob eine Datei richtig heruntergeladen wurde. Hier einige Beispiele für Hash-Werte:

Seite zum Ausprobieren von Hash-Algorithmen

http://www.xorbin.com/tools/sha256-hash-calculator

=== Seite zum Ausprobieren von Hash-Algorithmen http://www.xorbin.com/tools/sha256-hash-calculator

MD5

  • Haus

    ebacf61946ee81f386960ad2a09a147e

  • haus

    195efe600e8ee7550c43b93116820275

  • Laus

    c3694b483eed355a49954b09f345df09

=== MD5 * Haus + `ebacf61946ee81f386960ad2a09a147e` * haus + `195efe600e8ee7550c43b93116820275` * Laus + `c3694b483eed355a49954b09f345df09`

SHA-1

  • Haus

    22b78e2d5e887ec315104ccbe9430c30ceeb82a3

  • haus

    2b4e21824eae8daa555a12462de8ee95158d0167

  • Laus

    26aff90edc2ce45c123b7bf55d215f0bbf9e5971

=== SHA-1 * Haus + `22b78e2d5e887ec315104ccbe9430c30ceeb82a3` * haus + `2b4e21824eae8daa555a12462de8ee95158d0167` * Laus + `26aff90edc2ce45c123b7bf55d215f0bbf9e5971`

SHA-256

  • Haus

    50976ad58f5da02b7be89a224ef09b47ce3b5517623dd927576dc72ebca9214e

  • haus

    1a21f58f9570039d5e23f3619c8e9749bca19443fda30d6ebe352a90e69777cc

  • Laus

    e94a6083b91e11e50cbf911eef25c4fed3dd01c3848804801aa6b041fd2e76a3

=== SHA-256 * Haus + `50976ad58f5da02b7be89a224ef09b47ce3b5517623dd927576dc72ebca9214e` * haus + `1a21f58f9570039d5e23f3619c8e9749bca19443fda30d6ebe352a90e69777cc` * Laus + `e94a6083b91e11e50cbf911eef25c4fed3dd01c3848804801aa6b041fd2e76a3`

Gute Hash-Algorithmen haben gemeinsam, dass auch ähnliche Eingangswerte, die sich nur in einem Buchstaben unterscheiden, zu komplett unterschiedlichen Hash-Werten führen.

[NOTE] ==== Gute Hash-Algorithmen haben gemeinsam, dass auch ähnliche Eingangswerte, die sich nur in einem Buchstaben unterscheiden, zu komplett unterschiedlichen Hash-Werten führen. ====

Java hat die drei Hash-Algorithmen MD5, SHA-1 und SHA-256 bereits eingebaut, ab Java 9 findet man sogar den noch stärkeren Algorithmus SHA-3 mit verschiedenen Ausgabelängen.

Eine Anwendung, um zu einem Passwort einen Hash zu erzeugen, könnte die folgenden Zeilen enthalten:

Java hat die drei Hash-Algorithmen MD5, SHA-1 und SHA-256 bereits eingebaut, ab https://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUID-C23AFD78-C777-460B-8ACE-58BE5EA681F6[icon:external-link[]Java 9] findet man sogar den noch stärkeren Algorithmus SHA-3 mit verschiedenen Ausgabelängen. Eine Anwendung, um zu einem Passwort einen Hash zu erzeugen, könnte die folgenden Zeilen enthalten:
String passwort="passwort";
InputStream stream = new ByteArrayInputStream(passwort
        .getBytes(StandardCharsets.UTF_8));
// oder, um einen Hash für eine Datei zu bestimmen:
// InputStream stream = new FileInputStream("D:\\test.png");
try {
    // SHA-1, MD5 oder SHA-256
    System.out.println(Hash.checksum(stream, "SHA-256"));
} catch (Exception e) {
    e.printStackTrace();
}
Java
[source,java,indent=0] ---- String passwort="passwort"; InputStream stream = new ByteArrayInputStream(passwort .getBytes(StandardCharsets.UTF_8)); // oder, um einen Hash für eine Datei zu bestimmen: // InputStream stream = new FileInputStream("D:\\test.png"); try { // SHA-1, MD5 oder SHA-256 System.out.println(Hash.checksum(stream, "SHA-256")); } catch (Exception e) { e.printStackTrace(); } ----

Die auskommentierte Zeile erstellt einen Hash zu einer ganzen Datei, statt nur für ein Wort.

Die verwendete Klasse Hash in der Datei Hash.java könnte so aussehen:

Die auskommentierte Zeile erstellt einen Hash zu einer ganzen Datei, statt nur für ein Wort. Die verwendete Klasse `Hash` in der Datei `Hash.java` könnte so aussehen:
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import javax.xml.bind.DatatypeConverter;

public class Hash {
    public static String checksum(InputStream content,
            String hashFunction) throws Exception {

        byte[] buffer = new byte[8192];
        MessageDigest md = MessageDigest.getInstance(hashFunction);

        try (DigestInputStream dis = new DigestInputStream(content, md)) {
            while (dis.read(buffer) != -1);
        }
        return DatatypeConverter.printHexBinary(md.digest());
    }
}
Java
[source,java,indent=0] ---- import java.io.InputStream; import java.security.DigestInputStream; import java.security.MessageDigest; import javax.xml.bind.DatatypeConverter; public class Hash { public static String checksum(InputStream content, String hashFunction) throws Exception { byte[] buffer = new byte[8192]; MessageDigest md = MessageDigest.getInstance(hashFunction); try (DigestInputStream dis = new DigestInputStream(content, md)) { while (dis.read(buffer) != -1); } return DatatypeConverter.printHexBinary(md.digest()); } } ----

Einsatz beim Speichern von Passwörtern

Somit sollte man in Datenbanken nicht die Passwörter im Klartext speichern, sondern zumindest gehashte Passwörter.

Hierbei tritt aber das Problem auf, dass identische Passwörter zu identischen Hash-Werten führen. Mit Hilfe sogenannter Rainbow-Tabellen, die viele Passwörter mit ihren Hash-Werten gespeichert haben, kann man diese wieder relativ schnell in Klartext umwandeln.

Abhilfe schaffen hier Salt und Pepper.

=== Einsatz beim Speichern von Passwörtern Somit sollte man in Datenbanken nicht die Passwörter im Klartext speichern, sondern zumindest gehashte Passwörter. Hierbei tritt aber das Problem auf, dass identische Passwörter zu identischen Hash-Werten führen. Mit Hilfe sogenannter _Rainbow-Tabellen_, die viele Passwörter mit ihren Hash-Werten gespeichert haben, kann man diese wieder relativ schnell in Klartext umwandeln. Abhilfe schaffen hier https://en.wikipedia.org/wiki/Salt_(cryptography)[icon:external-link[]Salt] und https://en.wikipedia.org/wiki/Pepper_(cryptography)[icon:external-link[] Pepper].

  • Erkläre deinem Nachbarn den Unterschied zwischen Salt und Pepper.

  • Erweitere dein Programm, das einen Benutzer auf korrekte Eingabe von Benutzernamen und zugehörigem Passwort überprüft, sukzessive um

    • gehashte Passwörter

    • gehashte Passwörter mit Salt

    • gehashte Passwörter mit Salt und Pepper

[%autowidth,frame=none , cols=2 ] |=== |icon:question-circle[3x,role=red] a| * Erkläre deinem Nachbarn den Unterschied zwischen Salt und Pepper. * Erweitere dein Programm, das einen Benutzer auf korrekte Eingabe von Benutzernamen und zugehörigem Passwort überprüft, sukzessive um + ** gehashte Passwörter ** gehashte Passwörter mit Salt ** gehashte Passwörter mit Salt und Pepper |===

Zwei-Faktor-Authentifizierung

=== Zwei-Faktor-Authentifizierung

Um die Sicherheit bei der Anmeldung nochmals deutlich zu erhöhen, kann neben Benutzername und Passwort noch ein weiteres und jedes mal anderes Passwort abgefragt werden, das über ein weiteres Gerät (nicht das Gerät, mit dem man sich anmeldet) zur Verfügung gestellt wird. Diese zusätzliche Information wird als zweiter Faktor bezeichnet, woher der Name des Verfahrens kommt. Beim Online-Banking ist der zweite Faktor eine TAN aus der TAN-Liste.

Ein Gerät, das jeder von uns dabei hat, ist normalerweise ein Smartphone. Für dieses gibt es beispielsweise den Google-Authenticator für iOS oder Android.

Das Prinzip, das hinter der Zwei-Faktor-Authentifizierung steckt, ist das folgende (mehrmals klicken):

Um die Sicherheit bei der Anmeldung nochmals deutlich zu erhöhen, kann neben Benutzername und Passwort noch ein weiteres und jedes mal anderes Passwort abgefragt werden, das über ein weiteres Gerät (nicht das Gerät, mit dem man sich anmeldet) zur Verfügung gestellt wird. Diese zusätzliche Information wird als zweiter Faktor bezeichnet, woher der Name des Verfahrens kommt. Beim Online-Banking ist der zweite Faktor eine TAN aus der TAN-Liste. Ein Gerät, das jeder von uns dabei hat, ist normalerweise ein Smartphone. Für dieses gibt es beispielsweise den Google-Authenticator für https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8[icon:external-link[]iOS] oder https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2[icon:external-link[]Android]. Das Prinzip, das hinter der Zwei-Faktor-Authentifizierung steckt, ist das folgende (mehrmals klicken):

Weitere Informationen dazu findest du auf Wikipedia.

Eine Beschreibung, wie das Verfahren in Java umgesetzt werden könnte, kann auf diesem Blog nachgelesen werden, die darin erwähnte fertige Bibliothek wiederum ist auf Github zu finden mit weiteren Informationen zu deren Verwendung durch Maven.

Weitere Informationen dazu findest du auf https://de.wikipedia.org/wiki/Google_Authenticator[icon:external-link[] Wikipedia]. Eine Beschreibung, wie das Verfahren in Java umgesetzt werden könnte, kann auf http://thegreyblog.blogspot.de/2011/12/google-authenticator-using-it-in-your.html[icon:external-link[]diesem Blog] nachgelesen werden, die darin erwähnte fertige Bibliothek wiederum ist auf https://github.com/wstrange/GoogleAuth[icon:external-link[]Github] zu finden mit weiteren Informationen zu deren Verwendung durch Maven.

  • Erstelle ein Programm, das die Zwei-Faktor-Authentifizierung mit Hilfe von Google Authenticator testet.

  • Erweitere deinen Webserver um die Zweifaktor-Authentifizierung, indem zu jedem Benutzer der zugehörige geheime Schlüssel gespeichert und bei der Passwort-Abfrage berücksichtigt wird.

    Teste die Zwei-Faktor-Authentifizierung am Webserver mit deinem Handy.

[%autowidth,frame=none , cols=2 ] |=== |icon:question-circle[3x,role=red] a| * Erstelle ein Programm, das die Zwei-Faktor-Authentifizierung mit Hilfe von _Google Authenticator_ testet. * Erweitere deinen Webserver um die Zweifaktor-Authentifizierung, indem zu jedem Benutzer der zugehörige geheime Schlüssel gespeichert und bei der Passwort-Abfrage berücksichtigt wird. + Teste die Zwei-Faktor-Authentifizierung am Webserver mit deinem Handy. |===