digest auth mit django?

Django, Flask, Bottle, WSGI, CGI…
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Frage mich gerade, ob man nicht einen digest auth login in django implementieren könnte.

Hab mal gesucht, aber nichts entsprechendes gefunden.

Eine Implementierung von RFC2617 gibt es alerdings in paste:

http://svn.pythonpaste.org/Paste/trunk/ ... /digest.py

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

@jens: Das kommt darauf an, wie Django Benutzerpasswörter speichert. Um den für Digest-Auth nötigen HA1-Hash zu erhalten, ist das Benutzerpasswort im Klartext nötig. Man muss also entweder direkt den HA1-Hash oder das Klartext-Passwort in der Benutzerdatenbank speichern. Beides ist unschön.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Klartext Passwörter zu speichern ist natürlich eine schlechte Idee ;)

Irgendetwas zu speichern mit dem man ohne zusätzliches Wissen nutzten kann um sie ein zu loggen ist ebenfalls keine ganz so gute Idee ;)

Auf der anderen Seite:
  • * Wenn kein http*s* benutzt wird, kann man mit einem gültigen Session Cookie schon rein kommen.
    * Ohne alles, wird das Passwort im Klartext übertragen...
Damit es mir klarer wird ( einen guten Überblick über den Ablauf erhält man hier: http://en.wikipedia.org/wiki/Digest_acc ... n#Overview )

Demnach, wäre die einfachste Variante nach RFC 2069 das:

Code: Alles auswählen

HA1 = MD5(username + realm + password)
HA2 = MD5(method + digestURI)
Der Client sendet:

Code: Alles auswählen

MD5(HA1 + nonce + HA2)
In dem Fall muß ich auf dem Server mindestens HA1 speichern. Wenn jemand den DB Dump hat, kann er sich damit einloggen, kann aber das Klartext Passwort nicht rekonstruieren.

Erweitern kann man das ganze nach RFC 2517. Dabei blicke ich noch nicht ganz durch. Aber in der RFC ist ein Beispiel:

Das sendet der Server:

Code: Alles auswählen

         HTTP/1.1 401 Unauthorized
         WWW-Authenticate: Digest
                 realm="testrealm@host.com",
                 qop="auth,auth-int",
                 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
                 opaque="5ccc069c403ebaf9f0171e9517f40e41"
und das der Client zurück:

Code: Alles auswählen

         Authorization: Digest username="Mufasa",
                 realm="testrealm@host.com",
                 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
                 uri="/dir/index.html",
                 qop=auth,
                 nc=00000001,
                 cnonce="0a4f113b",
                 response="6629fae49393a05397450978507c4ef1",
                 opaque="5ccc069c403ebaf9f0171e9517f40e41"
Vom Server kommt:
* qop - ein String der festlegt "was der Server zusätzlich kann"
* nonce und opaque - zwei unterschiedliche zufalls MD5 hexdigest

Der Client erstellt:
* nc - ein Zähler (request counter)
* cnonce - einen einmalige Zufallszahl

Was muß man in dem Fall auf dem Server speichern???

btw. Django speichert einen MD5 Hash mit einem Salt Wert.


EDIT: Kann es sein, das auch mit allen RFC 2517 Zusätzen, auf dem Server der gleiche HA1 gespeichert werden muß?
Man könnte evtl. in dem realm einen salt Wert einfügen?!?

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

Der Server muss bei Digest Auth (egal ob nach RFC 2069 oder 2617) in der Lage sein, den HA1-Hash zu berechnen. Das kann er nur, wenn er entweder HA1-Hash oder Klartextpasswort zur Verfügung hat. Da hilft es auch nichts, "in das Realm einen Salt-Wert einzufügen" (was immer damit gemeint ist).

nonce, qop und opaque haben damit nichts zu tun, diese Werte dienen der Verifizierung eingehender Anfragen. In nonce und oqaque werden in der Regel Zeitstempel und/oder Zähler abgelegt. Das soll der Vermeidung von Replay-Attacken dienen.

Lies doch bitte RFC 2617, da ist das doch alles beschrieben (inkl. Sinn und Zweck der zusätzlichen Felder).
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

lunar hat geschrieben: "in das Realm einen Salt-Wert einzufügen" (was immer damit gemeint ist).
HA1 ist ja: MD5(username + realm + password)
OK, der realm sollte wohl eh immer speziell für die eine Seite sein. Ist der allerdings auf mehreren Servern gleich, hat man auch den selbe HA1.
Wenn man also zu jedem realm eine Zufälligen Salt beimischt ist der HA1 immer unterschiedlich. So ein bishen ähnlich als Passwörter nur als Hash ohne salt zu speichern, was allgemein nicht empfohlen wird. Aber gut, hier sind eh noch zwei Teile zum password dabei.

Was spricht dagegen den HA1 auf dem Server zu speichern?

Wenn man den normalen Django salt+password Hash in die Finger bekommen würde, kann man damit nicht all zu viel anfangen. Beim HA1 kann man sich allerdings einloggen. Schade.

Gibt es eine Alternative, die in allen Browsern implementiert ist???

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

Ach so, die Idee mit dem Salt bezieht sich auf serverseitige Speicherung. Dazu ist das Realm nicht gedacht. "Realm" bezeichnet einen eindeutigen Authentifizierungsbereich der Seite, und sollte daher nicht benutzerspezifisch, sondern nur seitenspezifisch sein!

Gegen die Speicherung des HA1-Hashs spricht, dass die Authentifizierungsmethode der Datenbank dann eine ganz bestimmte Art der Speicherung (e.g. Klartext oder HA1-Hash) aufzwingt, was den späteren Wechsel der Authentifizierungsmethode erschweren kann, und das der Authentifizierungsbereich aka Realm in den Hash einfließt, so dass man eine Seite nicht beliebig in Bereiche aufteilen kann, wenn man den HA1-Hash serverseitig speichert.
Wenn man den normalen Django salt+password Hash in die Finger bekommen würde, kann man damit nicht all zu viel anfangen. Beim HA1 kann man sich allerdings einloggen. Schade.
Das ist mehr oder weniger irrelevant. Wenn interne Werte aus der Benutzerdatenbank dem Angreifer in die Händen fallen können, bestehen viel größere Probleme. Wichtig ist vor allem, was bei der Authentifizierung übertragen wird, denn an frei durch den Äther gesendete Werte kommt man um Welten leichter heran als an die Passwort-Hashes aus der Benutzerdatenbank einer Seite.

Die in allen Browsern implementierte Alternative zu Digest-Auth heißt HTTPS …
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

lunar hat geschrieben:Die in allen Browsern implementierte Alternative zu Digest-Auth heißt HTTPS …
Du meinst X.509-Zertifikate? Wenn ich mich im Semester so umsehe kommen damit teilweise nichtmal Informatik-Studenten zurecht.

(Ob das jetzt mehr über X.509 oder Informatikstudenten aussagt daf jeder selbst entscheiden)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
lunar

Nein, ich meine einfach nur Transportverschlüsselung. Alle Gedanken über über eine Krücke wie Digest-Auth kann man sich dann völlig sparen, und einfach bedenkenlos eine normale Formular-Anmeldung mit Klartext-Passwort verwenden, ohne Konsequenzen für die Sicherheit fürchten zu müssen.

Zertifikate sind nettes Beiwerk, aber Transportverschlüsslung ist wirklich wichtig …
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

https in Django zu implementieren dürfte allerdings viel zu kompliziert sein ;)

Hab aber was gefunden:
HTTP Digest Authentication in Django: http://bitbucket.org/akoha/django-digest/wiki/Home
Dabei wird, ähnlich wie bei meinem JS-SHA-Login, parallel zum Django Password der HA1 generiert und gespeichert.

btw. Basic Auth gibt es auch, fertig: http://www.djangosnippets.org/snippets/243/

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

jens hat geschrieben:https in Django zu implementieren dürfte allerdings viel zu kompliziert sein ;)
Jupp einfach ne settings Variable abändern ist wirklich sau schwer…
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Was meinst du damit?

Ich meinte, eine https Implementierung in Django selbst. Damit man z.B. https mit dem dev Server hat bzw. wenn man von Apache aus keine Möglichkeit dazu hat.

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

jens hat geschrieben:bzw. wenn man von Apache aus keine Möglichkeit dazu hat.
Warum sollte man das nicht haben? Es ist 2010, SSL gibt es seit etwa 15 Jahren und es ist wohl die mit Abstand am weitesten verbreitete Transportverschlüsselung auf dem Planeten, da erwartet man dass ein Webserver das unterstützt.

Wäre ja lächerlich, das Rad neu zu erfinden.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

jens hat geschrieben:Ich meinte, eine https Implementierung in Django selbst. Damit man z.B. https mit dem dev Server hat bzw. wenn man von Apache aus keine Möglichkeit dazu hat.
Warum soll eine Applikation etwas machen was aufgabe des Frontends ist?
lunar

@jens: Transportverschlüsselung ist nicht Aufgabe der Anwendung, sondern des Servers. Wenn der Server bzw. der Hosting-Anbieter Transportverschlüsselung nicht bietet, eine sichere Authentifizierung aber Voraussetzung für den Betrieb ist, dann muss Du in logischer Konsequenz Server und/oder Anbieter wechseln.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

@lunar: Da hast du natürlich recht. Das ganze ist aber auch eine Budget Frage. Denn ein echtes Zertifikat kostet i.d.R. Geld.

Es geht hier nicht um einen Shop.

In erster Linie geht es mit darum keine Passwörter im Klartext zu verschicken, so wie es z.B. in diesem Forum der Fall ist.

Ich dachte Digest-Auth wäre da evtl. eine Alternative. Aber ich bleib dann wohl lieber bei meinem JS-SHA-Login. Den habe ich auch gerade erst neu implementiert, denn nun nutzte ich jQuery und alles geht per Ajax. (ist noch nicht comittet) Wenn ich Zeit finde, dann werde ich daraus mal eine separate "Reuseable Dango App" machen.

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

jens hat geschrieben:@lunar: Da hast du natürlich recht. Das ganze ist aber auch eine Budget Frage. Denn ein echtes Zertifikat kostet i.d.R. Geld.
Ein selbstsigniertes oder von CACert-signiertes Zertifikat kostet kein Geld und wenn man damit Leben kann dass man keine CA hat, der man vertrauen kann (wobei hier wiederrum die frage aufkommt welcher CA man tatsächlich auch vertrauen will) dann ist das von der Sicherheit der Daten genauso gut wie ein kostenpflichtiges Zertifikat.
jens hat geschrieben:Ich dachte Digest-Auth wäre da evtl. eine Alternative. Aber ich bleib dann wohl lieber bei meinem JS-SHA-Login. Den habe ich auch gerade erst neu implementiert, denn nun nutzte ich jQuery und alles geht per Ajax. (ist noch nicht comittet) Wenn ich Zeit finde, dann werde ich daraus mal eine separate "Reuseable Dango App" machen.
Also ich würde selbstsigniertes HTTPS etwa unendlich oft einem selbstzusammengebastelten SHA-JS-Whatever-Login vorziehen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
lunar

@jens: Was ist denn Dein „JS-SHA-Login“? Das bedeutet doch nicht etwa, dass Du das Passwort per Javascript hasht und erst dann versendest?! Dann wäre Digest-Auth nämlich eine um Welten bessere Alternative (und HTTPS sowieso) …

Und es muss doch im Übrigen auch kein Zertifikat einer anerkannten CA sein. Verschlüsseln kann man auch mit einem selbst ausgestellten Zertifikat. Da die meisten Benutzer (mich eingeschlossen) Zertifikate eigentlich nie prüfen, ist der Sicherheitsverlust eines selbst ausgestellten Zertifikats gegenüber einem "echten" CA-Zertifikat eigentlich recht marginal …
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mein "JS-SHA-Login" macht mehr als bloß einen Hash vom Password zu senden. Siehe: http://www.pylucid.org/permalink/42/sic ... ohne-https

Es ist schon ähnlich dem Digest Auth verfahren, aber:
1. es wird SHA1 statt MD5 verwendet
2. Auf dem Server wird nur ein Teil gespeichert mit dem man alleine nichts anfangen kann. (genau genommen wird ein Teil mittels XOR verschlüsselt)

Und Punkt 2 ist eigentlich das, was mich an Digest Auth am meisten stört.

Wie der JS-SHA-Login genau abläuft, steht hier: http://www.pylucid.org/permalink/34/js- ... seudo-code
Der eigentliche soucecode ist hier: http://trac.pylucid.net/browser/branche ... s/crypt.py

Bin für Kritik, wie man es noch besser manchen könnte, offen.


Wir müssen uns nicht darüber streiten, das https das beste wäre. Das ist mir auch klar. Aber wie viele Seiten setzten es ein, wenn es nicht gerade ein Shop ist? Diese Forum? Ubuntuusers? Fast niemand, wenn es nichts "kritisches" ist. Und meine Homepage sehe ich auch nicht als so "kritisch" an.

Aber wenn ich mich mal aus einem fremden Netz (z.B. an der Uni) einloggen möchte, ist es mit doch etwas unbehaglich, mein Passwort im Klartext zu verschicken. Zwar nutzte ich für jede Seite ein eigenes Passwort, aber dennoch...


EDIT: Ah, eine alternative wäre dann noch:
http://en.wikipedia.org/wiki/CRAM-MD5
http://en.wikipedia.org/wiki/HMAC

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

@jens: XOR ist keine Verschlüsselung :)

Wenn Du schon a priori davon ausgehst, dass die serverseitige Datenbank offen liegt, und man daraus HA1-Hashes auslesen kann, kann man über Sicherheit kaum sinnvoll diskutieren. Denn wenn der Angreifer tatsächlich so weit kommt, HA1-Hashes aus der Datenbank lesen zu können, dann ist das Auslesen des Hashes noch das geringste Problem. Schließlich kann der Angreifer dann unter Umgehung der Seite und deren Authentifizierungsmechanismen auch direkt die Datenbank manipulieren oder zumindest auslesen, und so noch weitaus größeren Schaden anrichten.

Insofern verstehe ich nicht, warum Du Dich daran, dass bei Digest-Auth eine verwertbare Vorstufe des Algorithmus serverseitig gespeichert werden muss, denn nüchtern betrachtet ist das eigentlich vollkommen egal, Dein Verfahren ist nicht sicherer oder unsicherer als Digest-Auth.

Beide Verfahren haben dieselben Probleme, und sind nur ein zusätzliches Hindernis, aber kein echter Schutz. Gegen einen Man-in-the-Middle-Angriff bieten beide Verfahren nicht den geringsten Schutz, sondern erhöhen der Aufwand nur ein kleines Stück.

Insofern ist HTTPS auch nicht das „beste“, sondern das einzig richtige und sichere.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Es muss nicht immer gleich ein Hacker auf der Maschine sein. z.B. kann man so keinen SQL Dump aus den Fingern geben, deswegen mag ich ehr ungern HA1 auf dem Server speichern... Und wenn das der einzige Mehrwert von JS-SHA-Login ist, dann ist das auch schon mal etwas, oder nicht?

Aber du hast natürlich recht, wenn ein Hacker auf der Maschine ist, ist eh alles verloren. Da hilft aber auch kein https ;)

Ach, in der Vergangenheit hat es auch Man-in-the-Middle Angriffe auf https Verbindungen gegeben... Und da sind wir wieder bei den Zertifikat Problem. Ohne ein echtes, hat der Mann in der Mitte es einfacher, oder nicht?

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