Medienbildung und Informatik

Fol­gen­de Auf­ga­ben haben Pro­gram­mier­an­fän­ger von mir nach ca. vier Ein­hei­ten Python bekom­men. Das Bei­spiel zeigt — fin­de ich — ganz gut, dass Medi­en­kom­pe­tenz und Infor­ma­tik sich sehr gut ergän­zen kön­nen, teil­wei­se viel­leicht sogar ein­an­der bedin­gen. Das Pro­blem der Pass­wort­län­ge und dem Pass­wort­auf­bau wird hier bewusst nicht ange­spro­chen, weil das pro­gram­mier­tech­nisch etwas anspruchs­vol­ler ist. Das kommt dann in der Fol­ge­stun­de.
Wei­ter­hin ist natür­lich auch das sha-2-Ver­schlüs­se­lungs­ver­fah­ren moder­ne­ren Ent­wick­lun­gen wie z.B. pbkdf2 weit unter­le­gen, aber auch pro­gram­mier­tech­nisch wesent­lich beherrsch­ba­rer. sha512 ist schon ganz ok, auch wenn heu­ti­ge Gra­fik­kar­ten ca. 200 Mil­lio­nen Schlüs­sel pro Sekun­de berech­nen.

Kryptografie

Immer wie­der hörst du davon, dass bei gro­ßen Anbie­tern Daten­bank­in­hal­te gestoh­len wer­den. In dem Arti­kel steht aller­dings nichts davon, dass Pass­wör­ter gestoh­len wer­den, son­dern Hash­es. Heu­te wirst du ler­nen, dass du jetzt schon ganz ein­fach viel bes­ser sein kannst als Lin­kedIn und das mit nur ganz weni­gen Code­zei­len in Python.

Um alles mög­lichst gut zu ver­ste­hen, musst du auf jeden Fall die bei­den oben ver­link­ten Arti­kel lesen oder wenigs­tens über­flie­gen.

Aufgabe 1:

Nimm eines dei­ner Pass­wör­ter und las­se fol­gen­des Pro­gramm lau­fen (z.B. auf https://try.jupyter.org ).

1
2
3
4
5
6
7
# wir weisen Python an, Kryptografiefunktionen zu laden
import hashlib
# wir fragen nach einem Passwort
crypted_phrase = input()
# Und geben den Hash des Passworts als MD5-Hash aus
print("Hash is:")
print(hashlib.md5(crypted_phrase.encode('utf-8')).hexdigest())

Nimm jetzt den Hash und kopie­re ihn auf die­se Sei­te. Nach Ein­ga­be der Sicher­heits­ab­fra­ge (reCap­t­cha) kannst du schau­en, ob der Hash dei­nes Pass­worts bereits bekannt ist (Wenn du das Ver­fah­ren mit dem Pass­wort „12345678“ durch­führst, wirst du sehen, dass das „geknackt“ wird.

Wie­der­ho­le das Ver­fah­ren mit einem dei­ner Pass­wör­ter und fol­gen­dem Pro­gramm (mit „12345678“ klappt es! — auch mit dei­nem Pass­wort?):

1
2
3
4
5
6
7
# wir weisen Python an, Kryptografiefunktionen zu laden
import hashlib
# wir fragen nach einem Passwort
crypted_phrase = input()
# Und geben den Hash des Passworts als MD5-Hash aus
print("Hash is:")
print(hashlib.sha512(crypted_phrase.encode('utf-8')).hexdigest())

Wenn dein Pass­wort auch im zwei­ten Fall „geknackt“ wur­de, hast du ein Pro­blem, wenn du Opfer eines Daten­bank­dieb­stahls wirst. Auch dein Anbie­ter wird nur Hash­es in einer Daten­bank spei­chern.

Infor­mie­re dich jetzt über den Unter­schied zwi­schen dem md5- und dem sha512-Ver­schlüs­se­lungs­ver­fah­ren. Python kann fol­gen­de Ver­fah­ren „von Natur aus“: md5, sha1, sha224, sha256, sha384, sha512.

Aufgabe 2:

Das Pro­blem ist schon lan­ge gelöst — mit nur weni­gen Code­zei­len mehr. Infor­mie­re dich über den Begriff „Salt“ in Ver­bin­dung mit Hash­es.

1
2
3
4
5
6
import hashlib
# Statt "somestring" kannst bzw. solltest du möglichst wirres Zeug hier reinschreiben
salt = "somestring"
crypted_phrase = input()
salted_password = crypted_phrase + salt
print(hashlib.md5(salted_password.encode('utf-8')).hexdigest())

Wenn du jetzt ver­suchst, den Hash cra­cken zu las­sen, klappt das nicht mehr, weil ein soge­nann­test „salt“ (Salz) zum Pass­wort hin­zu­ge­fügt wird. Bei unse­rem Pro­gramm ver­wen­det jedes Pass­wort jedoch den glei­chen Salt.

Auch dafür gibt es eine Lösung:

1
2
3
4
5
6
import hashlib, uuid
# Python schreibt nun für dich wirres Zeug hier hinein
salt = uuid.uuid4().hex
crypted_phrase = input()
salted_password = crypted_phrase + salt
print(hashlib.md5(salted_password.encode('utf-8')).hexdigest())

Hät­ten Lin­kedIn und ande­re die Benut­zer­pass­wör­ter mit einem siche­ren Algo­rith­mus (z.B. sha512) gehasht und mit einem Salt ver­se­hen, wäre der Dieb­stahl der Daten­ban­ken nicht so ein gro­ßes Pro­blem, da es sehr lan­ge dau­ern wür­de, die Pass­wör­ter aus den Hash­es zu errech­nen.

In der Pra­xis spei­chert man die Salts im Klar­text zusam­men mit den Hash­es, meist durch ein Trenn­zei­chen abge­setzt. Du kannst ja ein­mal über­le­gen, war­um das kein Pro­blem dar­stellt.

Aufgabe 3:

Schrei­be fol­gen­de Pro­gram­me

  1. Es wird zwei­mal ein Pass­wort abge­fragt und dazu ein Hash berech­net. Stim­men bei­de Hash­es (und damit die Pass­wör­ter) über­ein, soll das Pro­gramm die Aus­ga­be „Access gran­ted!“ machen, ansons­ten „Access denied!“ aus­ge­ben.
  2. Ein Pro­gramm fragt nach einem „Mas­ter­pass­wort“ (pass­word) und einem Domain­na­men (salt). Es berech­net dar­aus einen Hash, den man als Pass­wort für die betref­fen­de Web­sei­te benut­zen kann — wenn man immer das rich­ti­ge Mas­ter­pass­wort und den glei­chen Domain­na­men ein­gibt — qua­si ein ganz ein­fa­cher Pass­wort­ma­na­ger!

Verschlüsselung in Webapplikationen (MD5)

Pass­wör­ter gehö­ren nicht in die Hän­de von Drit­ten, auch nicht in die von Admi­nis­tra­to­ren. Daher wur­den für die Spei­che­rung von Pass­wör­tern soge­nann­te Fall­tür­me­cha­nis­men (trap­door mecha­nisms) ent­wi­ckelt:

Es ist zwar mög­lich, ein Pass­wort zu ver­schlüs­seln, nicht jedoch es wie­der zu ent­schlüs­seln.

Der Ver­schlüs­se­lungs­al­go­rith­mus funk­tio­niert also genau wie eine Fall­tür nur in eine Rich­tung. Das mag auf den ers­ten Blick sinn­los erschei­nen, ist aber eigent­lich sehr pfif­fig. Neh­men wir als Bei­spiel den weit ver­brei­te­ten MD5-Algo­rith­mus. Mit die­sem sichert fast jede Web­an­wen­dung in PHP ihre Pass­wör­ter ab. Dabei wird aus

123456=> MD5-Ver­schlüs­se­ler => e10adc3949ba59abbe56e057f20f883e

Die­se lan­ge Zei­chen­ket­te sieht der Admin. Er weiß aber des­we­gen das Pass­wort im Klar­text noch nicht, da der Weg

e10adc3949ba59abbe56e057f20f883e => MD5-Ent­schlüs­se­ler (Gibt es nicht) => Pass­wort

prin­zip­be­dingt ver­sperrt ist. Die dabei ent­ste­hen­de, lan­ge Zei­chen­ket­te wird „Hash” genannt.

Wenn man sich nun an einer Web­an­wen­dung (Mood­le, Joom­la, egroup­ware …) anmel­det, macht die Web­an­wen­dung fol­gen­des:

Benut­zer gibt Pass­wort im Klar­text ein => MD5-Ver­schlüss­ler => Hash1

Die­ser Hash1 wird nun mit dem Hash — nen­nen wir ihn Hash2 — ver­gli­chen, der in der Daten­bank für den User gespei­chert ist (er könn­te etwa bei der Regis­trie­rung erzeugt wor­den sein).

Stim­men bei­den Hash­es über­ein, hat der User das kor­rek­te Pass­wort ein­ge­ge­ben, weil der Ver­schlüs­se­lungs­me­cha­nis­mus ja immer gleich ist. Stim­men die Hash­es nicht über­ein, muss der Benut­zer ein fal­sches Pass­wort ein­ge­ge­ben haben.

Soweit so gut. Das ist auch die Erklä­rung dafür, dass einen — so man sein Pass­wort ver­ges­sen hat — stets ein neu­es Pass­wort zuge­wie­sen wird, denn der Admin kann das alte Pass­wort ja nicht wis­sen, son­dern ledig­lich ein neu­es set­zen.

Eigent­lich hört sich das Gan­ze recht sicher an — ist es bloß nicht, denn es gibt Angrif­fe gegen die­ses Ver­fah­ren, die aber alle­samt vor­aus­set­zen, dass der Angrei­fer an den Hash kommt.

Wei­ter­le­sen