Sicheres Speichern verschlüsselter Anmeldedaten in django

9

Ich arbeite an einer Python / Django-App, die unter anderem Daten mit einer Vielzahl anderer Dienste synchronisiert, einschließlich Samba-Shares, SSH-Servern, Google-Apps und anderen. Daher müssen die Anmeldeinformationen für den Zugriff auf diese Dienste gespeichert werden. Es wäre wohl eine schlechte Idee, sie als unverschlüsselte Felder zu speichern, da ein SQL-Injection-Angriff die Anmeldeinformationen abrufen könnte. Also müsste ich die Credits vor dem Speichern verschlüsseln - gibt es dafür zuverlässige Bibliotheken?

Sobald die Werte verschlüsselt sind, müssen sie entschlüsselt werden, bevor sie verwendet werden können. Es gibt zwei Anwendungsfälle für meine App:

  • Eins ist interaktiv - in diesem Fall würde der Benutzer das Passwort angeben, um die Zugangsdaten zu entsperren.
  • Die andere ist eine automatische Synchronisierung - dies wird durch einen Cron-Job oder ähnliches gestartet. Wo würde ich das Passwort behalten, um das Risiko von Exploits hier zu minimieren?

Oder gibt es einen anderen Ansatz für dieses Problem, das ich ergreifen sollte?

    
askvictor 15.10.2012, 21:49
quelle

3 Antworten

1

Das erste Speichern auf einem Server, das ausreicht, um sich bei einer Vielzahl von Systemen anzumelden, sieht wie ein Albtraum aus. Ein kompromittierender Code auf Ihrem Server wird alle, unabhängig von der Verschlüsselung, verlieren.

Sie sollten nur die Anmeldeinformationen speichern, die zur Ausführung Ihrer Aufgabe erforderlich sind (z. B. Dateien synchronisieren). Für Server sollten Sie einen Synchronisationsserver wie RSync verwenden, für Google die Protokolle wie OAuth usw. Auf diese Weise werden, wenn Ihr Server kompromittiert ist, nur die Daten und nicht der Zugriff auf Systeme verloren gehen.

Als Nächstes werden diese Anmeldedaten verschlüsselt. Für die Kryptographie empfehle ich Ihnen PYCrypto .

Für alle Zufallszahlen, die Sie in Ihrer Kryptographie verwenden würden, generieren Sie diese mit Crypto.Random (oder einer anderen starken Methode), um sicher zu gehen, dass sie stark genug sind.

Sie sollten verschiedene Anmeldeinformationen nicht mit demselben Schlüssel verschlüsseln. Die Methode, die ich empfehlen würde, ist dies:

  1. Ihr Server sollte das Master-Geheimnis haben M (abgeleitet von / dev / random). Speichern Sie es in der Datei, die root gehört und nur von root gelesen werden kann.
  2. Wenn Ihr Server mit root-Rechten beginnt, liest er die Datei in den Speicher und vor dem Serving-Client fallen seine Privilegien weg. Das ist bei Webservern und anderen Dämonen normal.
  3. Wenn Sie eine neue Berechtigung schreiben (oder eine vorhandene aktualisieren), generieren Sie einen zufälligen Block S . Nehmen Sie die erste Hälfte und berechnen Sie Hash K = H (S 1, M) . Das wäre Ihr Verschlüsselungsschlüssel.
  4. Verwenden Sie den CBC-Modus zum Verschlüsseln Ihrer Daten. Nehmen Sie den Initialisierungsvektor (IV) von S 2 .
  5. Speichern Sie S zusammen mit verschlüsselten Daten.

Wenn Sie entschlüsseln müssen, nehmen Sie einfach S , erstellen Sie das K und entschlüsseln Sie es mit derselben IV.

Für Hash würde ich SHA1 empfehlen, für die Verschlüsselung - AES. Hashes und symmetrische Cypher sind schnell genug, also würde es für größere Schlüsselgrößen nicht schaden.

Dieses Schema ist an einigen Stellen etwas überholt, aber auch das würde nicht schaden.

Aber denken Sie noch einmal daran, die beste Methode zum Speichern von Anmeldeinformationen besteht nicht darin, Anmeldeinformationen zu speichern, und wenn nötig, sollten Sie die am wenigsten privilegierten verwenden, mit denen Sie die Aufgabe ausführen können.

    
Rostislav Kondratenko 16.10.2012, 07:12
quelle
2

Ich habe das gleiche Problem und habe das in den letzten Tagen erforscht. Die Lösung von @Rostislav ist ziemlich gut, aber sie ist unvollständig und etwas veraltet.

Auf dem Algorithmus-Layer

Zuerst gibt es eine neue Bibliothek für die Kryptographie, die entsprechend Kryptografie genannt wird. Es gibt eine gute Anzahl von Gründen, diese Bibliothek anstelle von PyCrypto zu verwenden, aber die wichtigsten, die mich angezogen haben, sind:

  • Ein Kernziel ist, dass Sie sich nicht in den Fuß schießen können. Zum Beispiel hat es nicht stark veraltete Hash-Algos wie MD2.
  • Es hat eine starke institutionelle Unterstützung
  • 500.000 Tests mit kontinuierlicher Integration auf verschiedenen Plattformen!
  • Ihre Dokumentationswebsite hat stattdessen eine bessere SSL-Konfiguration ( nahezu perfekte A + Bewertung ) von eine mittelmäßige B-Bewertung )
  • Sie haben eine Offenlegungsrichtlinie für Sicherheitslücken.

Sie können mehr über die Gründe für das Erstellen der neuen Bibliothek auf LWN lesen.

Zweitens empfiehlt die andere Antwort die Verwendung von SHA1 als Verschlüsselungsschlüssel. SHA1 ist gefährlich schwach und wird schwächer . Der Ersatz für SHA1 ist SHA2, und außerdem solltest du deinen Hash wirklich salzen und ihn entweder mit bcrypt erweitern oder PBKDF2 . Salzen ist wichtig als Schutz gegen Regenbogen-Tische und Stretching ist ein wichtiger Schutz gegen Brute-Forcing.

(Bcrypt ist weniger getestet, aber dafür entwickelt, viel Speicher zu verwenden, und PBKDF2 ist langsam und wird von NIST empfohlen. In meiner Implementierung verwende ich PBKDF2. Wenn Sie mehr über die Unterschiede wissen wollen, lesen Sie dies .)

Für die Verschlüsselung sollte AES im CBC-Modus mit einem 128-Bit-Schlüssel verwendet werden, wie oben erwähnt - der sich nicht geändert hat, obwohl er jetzt in eine Spezifikation aufgerollt ist . Der Initialisierungsvektor wird automatisch in dieser Bibliothek für Sie generiert, so dass Sie das sicher vergessen können.

Auf der Schlüsselgenerierungs- und Speicherschicht

Die anderen Antworten stimmen ziemlich gut damit überein, dass Sie die Handhabung der Schlüssel sorgfältig in Betracht ziehen und sich für etwas wie OAuth entscheiden sollten, wenn Sie können. Aber angenommen, das ist nicht möglich (es ist nicht in meiner Implementierung), haben Sie zwei Anwendungsfälle: Cron Jobs und Interactive.

Der Anwendungsfall Cron-Job läuft darauf hinaus, dass Sie einen Schlüssel an einem sicheren Ort aufbewahren und ihn zum Ausführen von Cron-Jobs verwenden müssen. Ich habe das nicht studiert, deshalb werde ich hier nicht antworten. Ich denke, es gibt viele gute Möglichkeiten, dies zu tun, aber ich kenne den einfachsten Weg nicht.

Für den Anwendungsfall Interaktiv müssen Sie ein Benutzerkennwort erfassen, daraus einen Schlüssel generieren und diesen Schlüssel anschließend zum Entschlüsseln der gespeicherten Anmeldeinformationen verwenden.

Bring es nach Hause

So würde ich all das oben mit der Cryptography-Bibliothek tun:

%Vor%

Entschlüsselung sieht dann wie folgt aus:

%Vor%

Angriffe?

Nehmen wir an, Ihre DB ist ins Internet gelangt. Was kann ein Angreifer tun? Nun, der Schlüssel, den wir für die Verschlüsselung verwendet haben, hat den 100.000sten SHA256-Hash des gesalzenen Passworts Ihres Benutzers genommen. Wir haben das Salz und unsere Verschlüsselung in Ihrer Datenbank gespeichert. Ein Angreifer muss daher entweder:

  • Versuch Brute Force des Hash: Kombiniere das Salz mit jedem möglichen Passwort und hasse es 100.000 mal. Nehmen Sie diesen Hash und versuchen Sie es als Entschlüsselungsschlüssel. Der Angreifer muss 100.000 Hashes ausführen, nur um ein Passwort auszuprobieren. Das ist grundsätzlich unmöglich.
  • Probieren Sie jeden möglichen Hash direkt als Entschlüsselungsschlüssel aus. Das ist grundsätzlich unmöglich.
  • Probieren Sie eine Rainbow-Tabelle mit vorberechneten Hashes aus? Nein, nicht wenn zufällige Salze beteiligt sind.

Ich denke, das ist ziemlich solide.

Es gibt jedoch noch eine andere Sache, über die man nachdenken sollte. PBKDF2 wurde entwickelt, um langsam zu sein. Es erfordert viel CPU-Zeit. Das bedeutet, dass Sie sich DDOS-Angriffen öffnen, wenn Benutzer PBKDF2-Hashes generieren können. Sei darauf vorbereitet.

Postscript

All dies gesagt, ich denke, es gibt Bibliotheken, die einiges für Sie tun werden. Google rund um Dinge wie django verschlüsseltes Feld . Ich kann über diese Implementierungen keine Versprechungen machen, aber vielleicht wirst du etwas darüber lernen, wie andere das gemacht haben.

    
mlissner 31.05.2015 19:01
quelle
0

Vielleicht können Sie sich auf ein Mehrbenutzerschema verlassen, indem Sie Folgendes erstellen:

  • Ein Benutzer, der Django ausführt (z. B. django ), der nicht berechtigt ist, auf die Anmeldeinformationen zuzugreifen
  • Ein Benutzer mit diesen Berechtigungen (z. B. sync ).

Beide können sich in der Gruppe django befinden, damit sie auf die App zugreifen können. Danach erstellen Sie ein Skript (ein Django-Befehl, z. B. manage.py sync-external ), der die gewünschten Einstellungen synchronisiert.

Auf diese Weise hat der django -Benutzer Zugriff auf die App und das Synchronisierungsskript, aber nicht die Anmeldeinformationen, da nur der sync -Benutzer dies tut. Wenn jemand versucht, das Skript ohne die Anmeldeinformationen auszuführen, wird dies natürlich zu einem Fehler führen.

Das Linux-Berechtigungsmodell ist meiner Meinung nach eine "gute Idee", aber ich bin kein Sicherheitsexperte, also denken Sie daran. Wenn jemand etwas darüber zu sagen hat, was oben ist, zögere nicht!

    
F.X. 15.10.2012 22:10
quelle