Entwickler-Ecke

Off Topic - Sicherheitskonzept und Hashing


Boldar - Sa 22.11.14 17:55
Titel: Sicherheitskonzept und Hashing
Hallo,
ich habe folgende Situation:
Eine webseite, welche Passwort-Login anbietet. Die PW's in der db sind selbstverständlich gehasht und gesalzen.
Nun gibt es dazu einen (C#-)Client, welcher sich da anmeldet und daten per HTTP-Post überträgt.
Der Client soll das passwort speichern. Bisher steht das pw unverschlüsselt in einer Textdatei, das ist natürlich mist.
Jetzt dachte ich mir in etwa folgendes:
Ich hashe das PW beim Client vorm speichern und übertrage nur das gehashte pw zur Authentifizierung. Die in der Server-DB gespeicherten PW's hashe ich dann ein zweites mal und schreibe sie zurück in die db.
Sodass der Server das vom Client kommende (bereits einfach gehashte) PW nochmal hasht und mit der DB abgleicht. Damit sichere ich mich sowohl gegen Diebstahl meiner db ab (wenn jemand die db entwendet und ich es nicht merke, müsste er immernoch einen hash knacken um sich bei mir anzumelden, oder zwei hashes knacken um an das PW zu kommen, welches die User mit Sicherheit auch überall sonst benutzen.), als auch gegen Diebstahl des PW's beim user. (Wer das PW beim user Klaut, kann sich zwar bei meinem Service anmelden, aber nirgends sonst, ohne den hash zu knacken.
Ausserdem könnte ich das pw beim Client vor dem speichern asymetrisch mit dem Key des Servers verschlüsseln.
Ist das ganze so einigermaßen Sicher oder übersehe ich dabei was? Am besten müsste ich mich auch noch irgendwie die Daten selbst verschlüsseln und vorallem authentifizieren wegen Man in the Middle.
Ich weiss wohl dass man zur Authentifizierung SSL benutzen könnte, aber erstens kostet ein ssl key meist, zweitens wäre dass auch ein nicht unerheblicher Mehraufwand.
Authentifizieren will ich eigentlich auch eher den Client, also es geht mir darum dass niemand dem Server falsche Daten unterschieben kann. Andererseits braucht meine Software wohl auch später einen Autoupdater. Kommt man da um TLS nicht drumherum? Ich möchte ja auch nicht, dass jemand meinen Usern über meinen Autoupdater Malware unterjubeln kann.
Was meint ihr so dazu? Hier gibt es doch sicherlich Leute die schon ähnliche Sicherheitskritische Anwendungen entwickelt haben.
LG Boldar


jfheins - So 23.11.14 14:01

Das Konzept klingt für mich jetzt nicht so gut. Halt wie selbst ausgedacht, was bei Kryptografie eher schlecht ist.
Der Auffälligste Schwachpunkt ist die MitM-Attacke, also wenn der Bneutzer in einem offenen WLAN ist, dann kann jeder das gehashte Passwort mitlesen und das dann wieder an deine API schicken.

Einfachste Lösung: Zur Authentifizierung schickt der Server einen (kryptografischen!!!) Zufallswert (Nonce), eine User-ID und nen Zeitstempel in UTC. Der Client hasht nun das Ergebnis von "Zeitstempel + Nonce + UserID + Passworthash" und schickt es zur Authentifizierung zurück. Der Server kann dieselbe Operation durchführen und den Request authentifizieren.

Für die bessere Lösung brauchst du zunächst "API Keys" (kryptografischer Zufall, 256bit oder so). Also der Benutzer loggt sich online ein, und kann dort API-Keys generieren (und auch löschen). Ein API-Key besteht aus einer (z.B. fortlaufenden ID) und dem 256bit Schlüssel. Er generiert einen Key und Copy-Pasted diesen in deine Anwendung. (Dass der Key hier übers Netzwerk geht ist nicht ganz so schön)
Für einen Request kann der Client nun den Request zusammenbauen, inkl. Timestamp und API-Key ID und alles in einen String tun.

Jetzt kannst du die Daten mit dem API-Key verketten und Hashen. Der Server kann das gleiche tun, und weiß damit, dass der Request von diesem API Key kam. Dann noch prüfen, dass der API-Key tatsächlich zu dem Konto gehört und es sollte passen. Den letzten Timestamp speichern und nur Anfragen annehmen, die einen höheren Timestamp besitzen.

Schau dir auch mal diesen Post an: http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/
Geht alles sehr in die Richtung von OAuth ...


Boldar - So 23.11.14 22:19

user profile iconjfheins hat folgendes geschrieben Zum zitierten Posting springen:
Das Konzept klingt für mich jetzt nicht so gut. Halt wie selbst ausgedacht, was bei Kryptografie eher schlecht ist.
Der Auffälligste Schwachpunkt ist die MitM-Attacke, also wenn der Bneutzer in einem offenen WLAN ist, dann kann jeder das gehashte Passwort mitlesen und das dann wieder an deine API schicken.

Einfachste Lösung: Zur Authentifizierung schickt der Server einen (kryptografischen!!!) Zufallswert (Nonce), eine User-ID und nen Zeitstempel in UTC. Der Client hasht nun das Ergebnis von "Zeitstempel + Nonce + UserID + Passworthash" und schickt es zur Authentifizierung zurück. Der Server kann dieselbe Operation durchführen und den Request authentifizieren.


Ok, das gefällt mir.
Allerdings:
Wenn ich auf meiner Webseite ja auch Login anbieten will, ist dafür der einzige Weg das abzusichern SSL, oder?
(Beziehungsweise gegen MiTM ja sowieso nur mit SSL zwecks Authentifizierung, aber wenn man das mal außer acht lässt, wie sichere ich den Weblogin ab z.B. gegen simples sniffing im WLAN? Bzw. schütze mich vor replay attacks? Mit ner Javascript-funktion die eben das (also mit nonce und so) macht? Das wäre aber verflixt kompliziert.

user profile iconjfheins hat folgendes geschrieben Zum zitierten Posting springen:

Für die bessere Lösung brauchst du zunächst "API Keys" (kryptografischer Zufall, 256bit oder so). Also der Benutzer loggt sich online ein, und kann dort API-Keys generieren (und auch löschen). Ein API-Key besteht aus einer (z.B. fortlaufenden ID) und dem 256bit Schlüssel. Er generiert einen Key und Copy-Pasted diesen in deine Anwendung. (Dass der Key hier übers Netzwerk geht ist nicht ganz so schön)
Für einen Request kann der Client nun den Request zusammenbauen, inkl. Timestamp und API-Key ID und alles in einen String tun.

Jetzt kannst du die Daten mit dem API-Key verketten und Hashen. Der Server kann das gleiche tun, und weiß damit, dass der Request von diesem API Key kam. Dann noch prüfen, dass der API-Key tatsächlich zu dem Konto gehört und es sollte passen. Den letzten Timestamp speichern und nur Anfragen annehmen, die einen höheren Timestamp besitzen.

Ja, an sowas mit Keys hatte ich auch schon gedacht, ich befürchte erwarte aber dass das die User überfordert.

user profile iconjfheins hat folgendes geschrieben Zum zitierten Posting springen:

Schau dir auch mal diesen Post an: http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/
Geht alles sehr in die Richtung von OAuth ...

Danke, werde ich mir anschauen.


jfheins - So 23.11.14 23:22

Ja, dieses Prinzip funktioniert auch im Browser mit Javascript.
Du bastelst erst ein normales Formular. Das Javascript ersetzt dann das Passwortfeld mit einem andere Passwortfeld damit das Passwort nicht über die Leitung geht.
Beim Klick auf "Senden" wird dann alles gehasht und dieser Hash statt dem Passwort an der Server gesendet. Eigentlich gar nicht mal so kompliziert. Noch einfacher geht es, wenn du aktiviertes Javascript voraus setzen darfst.

Wenn ich mal wieder ne std. Zeit habe, könnte ich dir da auch ein Beispiel machen.

Aber besser ist immer noch SSL! Bei StartSSL kannst du dir ein Zertifikat generieren lassen, wenn dir die Domain gehört (geht nicht, falls dir nur ne Subdomain gehört) und das Gratis. Du musst dann nur jedes Jahr dran denken das zu erneuern.

Wenn du natürlich Kontrolle über Server und Client hast, geht das noch billiger: Erstelle dir einfach eine eigene CA und eigene Zertifikate. Dann kannst du das Teil für 3 Jahre ausstellen und Pinning betreiben. Also nicht prüfen "Ist das Stammzertifikat laut System vertrauenswürdig" sondern "Ist das wirklich MEIN Zertifikat?"
Mach Google in Chrome auch, und im Iran gab es dann auch mal ne Fehlermeldung á la "Das Zertifikat für google.com ist zwar vertrauneswürdig, aber Chrome weiß, dass es nicht wirklich von Google ist." :mrgreen:
Link: https://productforums.google.com/forum/?hl=en#!category-topic/gmail/share-and-discuss-with-others/3J3r2JqFNTw und https://www.eff.org/deeplinks/2011/08/iranian-man-middle-attack-against-google