Sinn oder Unsinn des PyLucids JS-MD5-Login...

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Aha! Nun wird es mir klar, was du meinst, nach dem ich es mal in Python code gegossen hab:

Code: Alles auswählen

import time
from md5 import new as md5_new


def md5(txt):
    return md5_new(txt).hexdigest()



salt = "s_%s" % time.time()
print "salt ist:", salt
print



print "In der DB ist gespeichert 'md5(salt + password)':"
db_md5pass = md5(salt + "Password")
print "db_md5pass:", db_md5pass
print



print "Server sendet challenge + salt zum client:"

challenge = "c_%s" % time.time()
print "challenge:", challenge
print



print "Client bildet 'md5(challenge + md5(salt + password))':"
client_response = md5(challenge + md5(salt + "Password"))
print "client_response:", client_response
print


print "Der Server vergleicht 'md5(challenge + db_md5pass)' mit 'db_md5pass':"
md5check = md5(challenge + db_md5pass)
print "md5check:", md5check

print

print "Login korrekt? ", md5check == client_response
So wie ich das sehe, hat das ganze allerdings einen Nachteil. In der DB werden zwar keine Klartext Passwörter gespeichert, aber zumindest die vollständigen Informationen mit dem man sich einloggen kann.

Will sagen, wenn jemand an diese Daten herran kommt, kann er sich mit den Informationen einloggen.

Durch den salt funktioniert das aber auch nur dort und nicht woanders. Aber immerhin.

Bei meiner aufwändigeren Variante, kann man mit den DB Daten IMHO nichts anfangen, weil es nur die Hälfte der nötigen Informationen sind.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

jens hat geschrieben:[...]
Bei meiner aufwändigeren Variante, kann man mit den DB Daten IMHO nichts anfangen, weil es nur die Hälfte der nötigen Informationen sind.
So habe ich das auch verstanden und deshalb finde ich deine Idee auch wirklich super :) Hat mMn bisher keine Forensoftware oder CMS so implementiert! :)

lg
BlackJack

jens hat geschrieben:Bei meiner aufwändigeren Variante, kann man mit den DB Daten IMHO nichts anfangen, weil es nur die Hälfte der nötigen Informationen sind.
Solange Du das nicht beweisen kannst, ist diese Aussage "wertlos".

Irgendwie finde ich auch die Diagramme, frühere Beschreibungen und den vorhandenen Quelltext nicht wirklich zusammenpassend. Da ist mal von geraden/ungerade Buchstaben die Rede, mal von den ersten vier und dem Rest und in `userhandling.py` steht im Kommentar, dass das JS-MD-5 noch nicht implementiert ist, aber irgend etwas wird da ja gemacht.

In PyLucid mag ich mich jetzt nicht einarbeiten. Kannst Du das Verfahren mal isoliert als Skript zeigen. Vielleicht mit Anlegen eines Benutzers und Datenspeicherung in einem gepickleten Dictionary oder so.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:Kannst Du das Verfahren mal isoliert als Skript zeigen. Vielleicht mit Anlegen eines Benutzers und Datenspeicherung in einem gepickleten Dictionary oder so.
Hervorragende Idee... Werde ich morgen mal machen...

btw. vielen dank für deine Geduld mir das normale Verfahren aufzuzeigen ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Ich werfe mal HMAC in den Raum.
TUFKAB – the user formerly known as blackbird
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

So, ich hab mal mein Verfahren versucht möglichst einfach in Python Code zu gießen. Verständlicher wird es, wenn man sich die Ausgaben dazu anschaut (s.u.):

Code: Alles auswählen

from md5 import new as md5_new


def md5(txt):
    return md5_new(txt).hexdigest()

def encrypt(txt, key): # Pseudo encrypt
    return "encrypted %s with %s" % (txt, key)

def decrypt(txt, key): # Pseudo decrypt
    txt, _, key2 = txt.split(" ", 3)[1:]
    assert key == key2
    return txt



print "\n\n------------ 1. Ein neuer User in der DB anlegen------------"
print "\n 1.1. Server sendet salt zum Client:",
salt = "s_123"
print "'%s'" % salt

print "\n 1.2. Eingabe des Passwortes auf dem Client:",
password = "Passwort"
print "'%s'" % password

print "\n 1.3. md5(password + salt):",
md5sum = md5(password + salt)
print "'%s'" % md5sum

print "\n 1.4. Übermittlung der MD5 Summe zum Server."



print "\n\n------------ 2. speichern des Users auf dem Server------------"

print "\n 2.1. Server trennt die MD5 in:",
md5_a = md5sum[:16]
md5_b = md5sum[16:]
print "md5_a: '%s' md5_b: '%s'" % (md5_a, md5_b)

print "\n 2.2. encrypt(md5_a, key=md5_b):",
md5checksum = encrypt(md5_a, key=md5_b)
print "'%s'" % md5checksum

print "\n 2.3. Speichern nur der verschlüsselten Checksum + salt\n"


print "_______________________________________________________________________"



print "\n\n------------ 3. Login eines Users------------"

print "\n 3.1. Server sendet salt '%s' + challenge zum client:" % salt,
challenge = "c_123"
print "'%s'" % challenge

print "\n 3.2. Eingabe des Passwortes auf dem Client:",
password = "Passwort"
print "'%s'" % password

print "\n 3.3. md5(password + salt):",
md5sum = md5(password + salt)
print "'%s'" % md5sum

print "\n 3.4. trennen der MD5 in:",
md5_a = md5sum[:16]
md5_b = md5sum[16:]
print "md5_a: '%s' md5_b: '%s'" % (md5_a, md5_b)

print "\n 3.5. md5_a2 = md5(md5_a + challenge):",
md5_a2 = md5(md5_a + challenge)
print "'%s'" % md5_a2

print "\n 3.6. Übermittlung von md5_a2 und md5_b."



print "\n\n------------ 4. check auf dem Server------------"

print "\n 4.1. aus der DB md5checksum: '%s'" % md5checksum

print "\n 4.2. decrypt(md5checksum, key=md5_b):",
md5checksum = decrypt(md5checksum, key=md5_b)
print "'%s'" % md5checksum

print "\n 4.3. md5(md5checksum + challenge):",
md5check = md5(md5checksum + challenge)
print "'%s'" % md5check

print "\n 4.4. Vergleich: %s == %s" % (md5check, md5_a2)
Die Asgaben:
------------ 1. Ein neuer User in der DB anlegen------------

1.1. Server sendet salt zum Client: 's_123'

1.2. Eingabe des Passwortes auf dem Client: 'Passwort'

1.3. md5(password + salt): '7522381eebd7c49a2522d09797ba20d2'

1.4. Übermittlung der MD5 Summe zum Server.


------------ 2. speichern des Users auf dem Server------------

2.1. Server trennt die MD5 in: md5_a: '7522381eebd7c49a' md5_b: '2522d09797ba20d2'

2.2. encrypt(md5_a, key=md5_b): 'encrypted 7522381eebd7c49a with 2522d09797ba20d2'

2.3. Speichern nur der verschlüsselten Checksum + salt

_______________________________________________________________________


------------ 3. Login eines Users------------

3.1. Server sendet salt 's_123' + challenge zum client: 'c_123'

3.2. Eingabe des Passwortes auf dem Client: 'Passwort'

3.3. md5(password + salt): '7522381eebd7c49a2522d09797ba20d2'

3.4. trennen der MD5 in: md5_a: '7522381eebd7c49a' md5_b: '2522d09797ba20d2'

3.5. md5_a2 = md5(md5_a + challenge): 'd3510bc87cf09bd7df69d180805e76fa'

3.6. Übermittlung von md5_a2 und md5_b.


------------ 4. check auf dem Server------------

4.1. aus der DB md5checksum: 'encrypted 7522381eebd7c49a with 2522d09797ba20d2'

4.2. decrypt(md5checksum, key=md5_b): '7522381eebd7c49a'

4.3. md5(md5checksum + challenge): 'd3510bc87cf09bd7df69d180805e76fa'

4.4. Vergleich: d3510bc87cf09bd7df69d180805e76fa == d3510bc87cf09bd7df69d180805e76fa
Zu beachten ist, die verschlüsselte MD5 Summe wird bei Punkt 2.3 und 4.1. anhand des Usernamen in der DB gespeichert bzw. gelesen.


Wie man sieht ist in der DB nur die hälfte der MD5 Summe gespeichert (Punkt 2.3) und das auch noch verschlüsselt mit der anderen hälft.

Wenn jemand also an die DB Daten kommt, kann er damit nichts anfangen. Das wäre anders, wenn ich auf die Verschlüsselung verzichte.

EDIT: Noch ein Hinweis. In genau der Form ist es z.Z. auch in PyLucid nicht implementiert. Zwar sehr ähnlich, aber nicht ganz. Mir ist ja erst durch diesen Thread aufgefallen, das man das Verfahren noch etwas optimieren kann ;)
Ich werde das aber erst so wie hier implementieren, wenn ein "Passwort reset" möglich ist :)

Im übrigen steht im Wiki unter [wiki]JensDiemer/CryptoIdee[/wiki] noch eine andere Idee, einses noch sicheren Verfahren, was auf http://de.wikipedia.org/wiki/Diffie-Hellman beruht. Da es Diffie-Hellman nicht als fertiges JavaScript gibt hat sich das aber erledigt. Außerdem ist das Verfahren bei einem man-in-the-middle auch nicht sicher. Zudem kommt noch das es wohl eindeutig Overkill ist, in anbedracht von Session-Hijacking :)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

jens hat geschrieben:Wie man sieht ist in der DB nur die hälfte der MD5 Summe gespeichert (Punkt 2.3) und das auch noch verschlüsselt mit der anderen hälft.

Wenn jemand also an die DB Daten kommt, kann er damit nichts anfangen. Das wäre anders, wenn ich auf die Verschlüsselung verzichte.
Kann ich mir, wenn ich die DB-Daten habe, nicht einfach irgendeinen Schlüssel ausdenken? Wenn ich die DB-Daten damit entschlüssele, dann habe ich zwei Hälften die ich für ein Login verwenden kann und die der Prüfung standhalten.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:Kann ich mir, wenn ich die DB-Daten habe, nicht einfach irgendeinen Schlüssel ausdenken? Wenn ich die DB-Daten damit entschlüssele, dann habe ich zwei Hälften die ich für ein Login verwenden kann und die der Prüfung standhalten.
Hm. Interessante Frage... Aber ich glaube: "nein".

Es kommt auf das Verschlüsselungsverfahren an. In frage kommen ja DES bzw. Rijndael, siehe: http://www.python-forum.de/topic-8075.html

Wie soll man also die Daten so einfach entschlüsseln, es dürfte nur der eine richtige Schlüssel passen. Also müsste man ein BruteForce versuchen um den richtigen Key zu finden.

Oder hab ich da einen Denkfehler?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

jens hat geschrieben:Wie soll man also die Daten so einfach entschlüsseln, es dürfte nur der eine richtige Schlüssel passen. Also müsste man ein BruteForce versuchen um den richtigen Key zu finden.
Es geht ja gar nicht darum das "Original" zu herauszufinden. Ich kann `decrypt()` doch einfach mit einem zufälligen Schlüssel `b` auf den verschlüsselten Eintrag loslassen und bekomme damit etwas das ich mal `a` nenne. Mit diesen beiden Werten müsste jetzt eine Authentifizierung möglich sein. Client bekommt `challenge` und sendet `hash(a + challenge)` und `b` an Server. Der entschlüsselt den Eintrag mit `b`, bekommt `a` heraus und prüft ob `hash(a + challenge)` gleich dem gesendeten ist. Ist es -> Bingo. :-)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:Ich kann `decrypt()` doch einfach mit einem zufälligen Schlüssel `b` auf den verschlüsselten Eintrag loslassen und bekomme damit etwas das ich mal `a` nenne.
Nein. decrypt() sollte eine Exception liefern, wenn der Key nicht der richtige ist.
z.Z. bei meiner XOR Variante, habe ich deswegen ja auch den hash() und jetzt die MD5() in den encrypteten Daten drin.
d.h. es wird zwar die XOR Operartion immer gemacht, egal welcher Key, aber danach muß die checksumme auch stimmen und das tut sie nicht, wenn der Key ein falscher war.

Mit DES bzw. Rijndael statt einem XOR, dürfte IMHO die Entschlüsselung nie mit einem falschen Key gehen. Aber das muß ich noch testen, ob ich da auch mit checksummen arbeiten muß.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

jens hat geschrieben:Nein. decrypt() sollte eine Exception liefern, wenn der Key nicht der richtige ist.
z.Z. bei meiner XOR Variante, habe ich deswegen ja auch den hash() und jetzt die MD5() in den encrypteten Daten drin.
d.h. es wird zwar die XOR Operartion immer gemacht, egal welcher Key, aber danach muß die checksumme auch stimmen und das tut sie nicht, wenn der Key ein falscher war.
Ah, okay. Dann ist der einzige Vorteil wenn man den DB-Inhalt kennt, dass man in aller Ruhe lokal/verteilt Schlüssel durchprobieren kann. Direkt mit einem Suchraum von 2**64. Nicht so praktikabel, also wird man am schwächsten Glied, dem Benutzerpasswort angreifen, und es mit einem Wörterbuchangriff versuchen.
Mit DES bzw. Rijndael statt einem XOR, dürfte IMHO die Entschlüsselung nie mit einem falschen Key gehen. Aber das muß ich noch testen, ob ich da auch mit checksummen arbeiten muß.
Doch da musst Du auch ein Signatur irgendwo speichern, wenn Du das Ergebnis der Entschlüsselung testen möchtest.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ja gut einen Wörterbuchangriff kann man wohl nie verhindern ;)

Du hast recht, es ist "nur" ein Suchraum von 2**64, weil es ja nur eine halbe MD5 Summe ist. Aber egal. Das ist immerhin eine Zahl mit 20 Stellen und dürfte erstmal reichen ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Irgendwie erinnert mich das ganze Konzept etwas an aSSL welches Fefe verrissen hat :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Es ist allerdings schon etwas anderes... Dort wird versucht Daten wirklich zu verschlüsseln um diese hin und her schicken zu können.
Ich arbeite dagegen nur an einer sichereren Authentifizierung mit Hilfe von MD5 Checksummen.
Eine Verschlüsselung brauche ich nur auf dem Server und diese dient nur zum vergleichen der MD5 summen. Also um zu prüfen ob das ursprünglich eingegebene Passwort auch wirklich richtig ist.

Im übrigen werde ich die Tage eine erste Alpha Version mit dem neuen auth Modul fertig haben :lol:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

So, in der neuen v0.7.2alpha ist es nun genau so verwirklicht, wie hier skizziert:

http://pylucid.net/trac/browser/trunk/t ... gin_doc.py

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Was man nicht so alles im Netz findet: http://pajhome.org.uk/crypt/md5/auth.html

Sehr Interessant... Hätte ich die Seite mal vorher gekannt...

Dort gibt es auch ein SHA-1 in JavaScript...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

jens hat geschrieben:Ja gut einen Wörterbuchangriff kann man wohl nie verhindern ;)
Verhindern nicht, aber stark einschränken auf jeden Fall: Nach mehreren fehlgeschlagenen Versuchen kann man den Account für eine gewisse Zeitspanne oder dauerhaft bis zur Freischaltung per Email oder durch einen Administrator sperren.

Und natürlich mit Passwörtern, die nicht in Wordlists stehen (auch nicht teilweise).

jens hat geschrieben:Dort gibt es auch ein SHA-1 in JavaScript...
Wow, interessante Idee einen Sicherheitsmechanismus davon abhängig zu machen, dass etwas anderes aktiviert sein muss, das zudem auch noch die Sicherheit gefährdet.

Edit: Hmm, der gute Autor von aSSL scheint auch ein Problem mit seinen Redirects zu haben. Wenn ich Fefes Link auf http://assl.sullof.com/assl/howitworks.asp folge, wird die URL zu dieser (1812 Zeichen lang...) umgewandelt bis es einen Abbruch wegen fehlerhafter Redirection gibt. Na gut.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Y0Gi hat geschrieben:Nach mehreren fehlgeschlagenen Versuchen kann man den Account für eine gewisse Zeitspanne oder dauerhaft bis zur Freischaltung per Email oder durch einen Administrator sperren.
Das werde ich auf jeden Fall demnächst realisieren. Da PyLucid allerdings es als CGI läuft, gibt es so oder so ein Limit der Request-Anfragen. Somit ist es jetzt auch Sinnlos einen Bruteforce zu versuchen.
Eine grobe Schätzung mit meinem simple_web_bench zu urteilen, kann der Server ca. 3 Request pro Sekunden verarbeiten. Dabei wird allerdings nur das Login Formular geholt und nicht ausgewertet. Die Auswertung dürfte wahrscheinlich noch etwas weniger sein.
Ich vermute das es eh ein Limit von Apache aus gibt, das bei einem Bruteforce/DOS zum tragen kommt...
Y0Gi hat geschrieben:Und natürlich mit Passwörtern, die nicht in Wordlists stehen (auch nicht teilweise).
Naja, Was soll man machen, wenn die User ein super einfaches Passwort nehmen? Pauschal eine google Suche machen und dann warnen, wenn zuviele Treffe auftauchen???
Das wäre zwar nett, aber dann verrät man das Passwort immer google, was bescheuert wäre ;)

Y0Gi hat geschrieben:
jens hat geschrieben:Dort gibt es auch ein SHA-1 in JavaScript...
Wow, interessante Idee einen Sicherheitsmechanismus davon abhängig zu machen, dass etwas anderes aktiviert sein muss, das zudem auch noch die Sicherheit gefährdet.
Hä? Wie meinst du das denn jetzt???
Ich könnte halt das JS-MD5 Skript mit dem SHA-1 tauschen. Bringt zwar auch keinen mehrgewinn, aber ist netter ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

jens hat geschrieben:Naja, Was soll man machen, wenn die User ein super einfaches Passwort nehmen? Pauschal eine google Suche machen und dann warnen, wenn zuviele Treffe auftauchen???
Das wäre zwar nett, aber dann verrät man das Passwort immer google, was bescheuert wäre ;)
Schonmal was von John, the Ripper gehört?
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ja, und was willst du mir damit sagen???

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten