Ohne Kryptografie gäbe es keinen Datenschutz und keine Privatsphäre im Netz. Bankkonten, E-Mails, Social-Media-Accounts – private Daten wären ohne Kryptografie einfach zu hacken.
Ein Computer führt grundsätzlich aus, was man ihm sagt, auch wenn das manchmal schwer zu glauben ist. Nur manchmal wollen wir nicht, dass er etwas tut – zum Beispiel sensible Daten freigeben. Hier kommt Kryptografie ins Spiel, die Wissenschaft vom Verschlüsseln von Informationen. Verschlüsselt wurden Informationen schon lange bevor es Computer gab. Schon im alten Ägypten wurden beispielsweise mythologisch-religiöse Texte verschlüsselt, indem zur Referenzierung auf Gottheiten spezielle Hieroglyphen verwendet wurden, die nur Geistliche lesen konnten. Julius Cäsar (100 v. Chr. bis 44 v. Chr.) schrieb verschlüsselte Nachrichten an seine Generäle, indem er Buchstaben des Alphabets verschob. Bekannt wurde diese Chiffre als die Cäsar-Chiffre.
Was ist eigentlich ein Hash?
Computergestützte Kryptografieverfahren spielen etwa seit 1970 eine wichtige Rolle. Vereinfacht gesagt werden dabei Daten mithilfe eines Algorithmus verschlüsselt. Ohne die entsprechenden Berechtigungen ist es – im Idealfall – nicht möglich, sie zu entschlüsseln. Als Entwickler:innen müsst ihr zwar die komplexe Mathematik dahinter nicht verstehen, jedoch solltet ihr Konzepte wie Caching, Verschlüsselung und Signierung kennen.
Eines der gängigsten kryptografischen Konzepte ist ein sogenannter Hash. Das Wort ist kulinarischen Ursprungs und bedeutet soviel wie „kleinhacken und mischen“, was eigentlich perfekt beschreibt, was ein Hash tut. Einer Hash-Funktion wird eine Eingabe von beliebiger Länge übergeben. Die Funktion gibt dann einen Wert mit einer festen Länge zurück, den sogenannten Hash. Dieser lässt keine Rückschlüsse auf die Eingabe zu. Bei gleicher Eingabe wird immer die gleiche Ausgabe erzeugt. Ein Hash muss zudem schnell zu berechnen und eindeutig sein.
Hashes können Daten – beispielsweise Passwörter – verschlüsseln
Das sind nützliche Eigenschaften, die es Entwickler:innen beispielsweise ermöglichen, Daten verschlüsselt zu speichern, ohne ihren wahren Wert kennen zu müssen – etwa bei der Speicherung von Passwörtern in einer Datenbank. Die Passwörter einfach im Klartext in der Datenbank zu speichern, wäre zwar auch möglich, ist aber nicht zu empfehlen. Verschaffen sich Angreifer:innen Zugriff auf die Datenbank, könnten sie die dort gespeicherten Passwörter ganz einfach auslesen und nutzen. Sind die Daten jedoch gehasht, müssen vorher die Hashes geknackt werden.
Implementieren können Entwickler:innen eine Hash-Funktion beispielsweise in Node Crypto, dem Cryptomodul von Node.js. Alles was ihr dafür braucht, ist node.js und eine JavaScript-Datei im Code-Editor eurer Wahl:
const { createHash } = require('crypto');
function hash(input) {
return createHash('sha256').update(input).digest('hex'));
Als Erstes wird die createHash
-Funktion aus Node Crypto importiert. Anschließend wird eine eigene benutzerdefinierte Funktion definiert, die einen String als Input annimmt und einen Hash-String zurückgibt. Im oben stehenden Beispiel heißt diese Funktion hash
.
Dann muss der zu verwendende Hash-Algorithmus definiert werden. Im Beispiel ist das Sha256, Alternativen wären beispielsweise Argon2 oder md5. Zweiterer gilt allerdings als veraltet, ersterer ist nicht in Node Crypto verfügbar.
Innerhalb der Hashing-Funktion createHash wird update
mit dem entsprechenden input
-Value aufgerufen. Um die Rückgabe eines Hashs zu definieren, dient digest
– zusammen mit dem Format, in dem der Hash zurückgegeben werden soll. Im Beispielcode wird das Hexadezimalformat ('hex')
verwendet, eine andere verbreitete Option ist base64.
Dieser Funktion kann dann eine Eingabe, im Beispiel eben ein Passwort übergeben werden. Ein console.log()
von hash1
zeigt euch dann die immer gleiche Zeichenfolge im Hexadezimalformat. Aussehen kann diese beispielsweise so:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
.
let password = 't3n – digital pioneers'
const hash1 = hash(password);
console.log(hash1)
Um zwei gehashte Passworteingaben miteinander abzugleichen, wird jetzt eine zweiter Hash – hash2
– erstellt und mit dem ersten verglichen:
password = 't3n – digital news';
const hash2 = hash(password);
const match = hash1 === hash2;
console.log(match ? ' 😊 passwords match ' : ' 🤨 passwords don't match ');
Stimmen sie überein, würde bei einem console.log()
von hash2
dieselbe lange Zeichenfolge ausgegeben. Da sie im Beispiel nicht übereinstimmen, wäre der Output des console.log()
im Code-Snippet 🤨 passwords don't match
.
Hashes allein reichen nicht aus
Das sind die Basics der Funktionsweise eines Hashes. Hashes sind nützlich, reichen allein jedoch nicht aus, um ein Passwort sicher in einer Datenbank zu speichern. Das Problem liegt in der oben beschriebenen Eigenschaft, bei gleichem Input immer den selben Output zu generieren.
Der Grund: Haben Angreifende Zugriff auf eine Datenbank mit gehashten Passwörtern erlangt, ist die Wahrscheinlichkeit hoch, dass sich darin auch Passwörter wie Passwort oder 123456 finden. Die daraus resultierenden Hashes können Angreifer:innen dann einfach recherchieren – und schon haben sie einen Teil der Passwörter in der Datenbank geknackt.
Für mehr Sicherheit bei kryptografischen Hash-Funktionen sorgt ein weiteres kryptografisches Konzept, das sogenannte Salt.
„…Für mehr Sicherheit bei kryptografischen Hash-Funktionen sorgt ein weiteres kryptografisches Konzept, das sogenannte Salt.“
Durch die Formulierung dachte ich kurz es geht jetzt auf Seite 2 weiter wo kurz etwas zum Salt erklärt wird, schade – aber guter Artikel.
Ging mir genauso. Es wäre nett wenn hier dann wenigstens der Hinweis auf den Artikel zu Salt kommen würde!