Ich sehe gelegentlich Fragen, wie Benutzerkennwörter für eine Webanwendung sicher gespeichert werden können (mit einem RDBMS spreche ich nicht von Facebook oder Twitter). Die übliche Antwort lautet "Salt das Passwort, dann Hash es mit einem starken Algorithmus wie TDES oder SHA512".
Meine Frage lautet: Warum sollte ich mich als RDBMS-Benutzer überhaupt mit der problematischen Speicherung von Passwörtern beschäftigen, da die meisten Engines über einen integrierten Authentifizierungsmechanismus verfügen?
Wenn beispielsweise ein Benutzer X in meiner Webanwendung ein Kontonutzerkennwort Y erstellen möchte, wie wird die folgende Abfrage falsch ausgegeben:
CREATE USER X WITH ENCRYPTED PASSWORD Y IN GROUP baseuser;
Dann kann der Benutzer in meiner Anwendung mit seinen Anmeldeinformationen eine Verbindung zur Datenbank herstellen, und ich muss mich überhaupt nicht um die Kennwortverwaltung kümmern.
Ich sehe mehrere Vorteile dieser Methode:
- Wenn das RDBMS entscheidet, dass der Verschlüsselungsalgorithmus geändert werden muss, muss ich nichts anfassen, nur um die Sicherheitsupdates anzuwenden.
- Es ist für mich einfach, die Benutzerberechtigungen zu verwalten. Wenn ein Benutzer in die Rolle eines Administrators befördert wird, muss ich den Benutzer nur der entsprechenden Gruppe hinzufügen.
- SQL-Injektionen sind jetzt bedeutungslos, da ich Berechtigungen verwalte, um jedem Benutzer in der Datenbank genau das zu ermöglichen, was ich zulassen möchte (z. B. in einem Forum wie SO, Hinzufügen neuer Beiträge, Beantworten von Beiträgen, Kommentieren und Bearbeiten / Löschen seiner eigenen Fragen / Antworten / Kommentare);
- Ein Benutzerkonto "anonym" kann für nicht authentifizierte Verbindungen zu meiner Anwendung verwendet werden.
- Jeder Benutzer ist der Eigentümer der von ihm bereitgestellten Daten.
Aber bei praktisch jeder Frage, die ich zu diesem Thema sehe, scheint es einen allgemeinen Konsens zu geben, dass dies nicht die Art und Weise ist, wie Dinge getan werden müssen. Meine Frage ist: warum?
Hinweis: Der dritte Punkt wird von Richtlinien in PostgreSQL und Sicherheitsrichtlinien in Microsoft SQL Server zugelassen. Mir ist klar, dass diese Konzepte Neulinge sind, aber warum wird die von mir beschriebene Technik nicht zur Standardmethode für den Umgang mit Benutzerkonten?
Antworten:
Für viele Anwendungen möchten sie nicht, dass einzelne Benutzerkonten eine Verbindung zur Datenbank herstellen. Die Benutzer / Kennwörter / Rechte / Berechtigungen werden alle auf der Anwendungsebene verarbeitet, und ein einziges dediziertes Dienstkonto wird verwendet, um eine Verbindung zum Datenbank-Backend herzustellen.
Als DBA möchte ich nicht auf Datenbankebene die 10.000 aktiven Benutzer einer mittelgroßen öffentlich zugänglichen Webanwendung oder die 2+ Millionen Benutzer einer plötzlich beliebten App verwalten müssen.
In einem sehr realen Sinne ist dies ein Unterschied in der Philosophie zwischen Anwendungsentwicklern und Datenbankentwicklern / Datenbankadministratoren.
Viele / die meisten Anwendungsentwickler werden die Verantwortung für wichtige Aspekte der App-Funktionalität und / oder Geschäftsregeln nicht auf die Datenbankebene übertragen wollen. Stattdessen betrachten sie die Datenbank als Werkzeug zum einfachen Speichern und Abrufen von Daten.
In einigen Fällen kann dies kurzsichtig sein; Viele RDBMS verfügen über fantastische Funktionen, die das Leben von App-Entwicklern erheblich vereinfachen können (Sicherheit auf Zeilenebene, Spaltenindizes, Dateistream-Speicher usw.).
Einige dieser cooleren Funktionen sind jedoch nur in neueren Versionen verfügbar, und Unternehmen können vorhandene Umgebungen nicht immer schnell aktualisieren (siehe diese Tabelle aus dem Jahr 2014 ).
In anderen Fällen wird die Behandlung dieser Dinge auf der Anwendungsebene bevorzugt (und nicht nur aus Gründen der Portabilität der Datenbankplattform denke ich offen, dass die Behauptung übertrieben ist).
quelle
Die Trennlinie wird zu diesem Zeitpunkt etwas flauschig, aber ich würde Benutzer und Berechtigungen auf Datenbankebene als Teil des Schemas betrachten, nicht als Teil der Daten, und im Allgemeinen haben Anwendungen keinen Platz, um das Schema zu ändern (es gibt, wie immer Ausnahmen von dieser Regel).
Ich möchte den Anwendungen lieber nicht die Berechtigungen erteilen, die sie zum Verwalten von Schemaobjekten (Anmeldungen, Benutzer und Berechtigungen) benötigen, da neue Benutzer benötigt werden und alte verlassen werden. Wenn diese Anwendung gehackt wird, hat der Angreifer Zugriff auf diese Berechtigungen Dies erleichtert das weitere Öffnen der Datenbank. In MS SQL Server sind Anmeldungen, sofern Sie keine vollständig enthaltenen Datenbanken verwenden, Objekte auf Serverebene. Daher müssen Sie Rechte über die einzelne Anwendungsdatenbank hinaus vergeben, was das Risiko noch erhöht.
Selbst wenn Sie auf Datenbankebene Konten pro Anwendungsbenutzer haben, benötigen Sie Benutzerkonten auf Anwendungsebene, um nicht authentifizierte Anforderungen zu verarbeiten. Dies bedeutet, dass die Anwendung Informationen aus der Datenbank benötigt, bevor sich der Anwendungsbenutzer erfolgreich authentifiziert hat (möglicherweise auch) Statusinformationen auf dem Begrüßungs- / Anmeldebildschirm anzeigen?).
Auch wenn die Portabilität zwischen Datenbank-Engines ein Ziel ist (vielleicht möchte Ihre App sowohl auf MySQL als auch auf Postgres ausgeführt werden können?), Müssen Ihre Anwendungen die Benutzer- / Anmeldeverwaltungsfunktionen für jede Engine abstrahieren, da sie nicht Standard zwischen ihnen sind - Wenn Sie sich darum bemühen, können Sie Kennwörter auch selbst implementieren und die gewünschten Verwaltungsoptionen erhalten, anstatt den niedrigsten gemeinsamen Funktionsumfang der Engines zu akzeptieren.
quelle
Wiederholung der Frage
Die einfachste Antwort ist, dass Sie dies tun müssen. Sie speichern weiterhin Passwörter in Ihrer alternativen Methode. Sie verwenden lediglich das integrierte System der Datenbank, um den Speicher zu verwalten. Ihre Methode ist also nur so gut wie die Ihrer Datenbank. Das ist vielleicht immer noch besser als alles, was Sie sonst tun, aber es vermeidet nicht die Speicherung. Es geht wirklich nur darum, Codierungsspeicher zu vermeiden.
Es könnte auch nicht besser sein. Wenn ich eine Datenbank kompromittiere und Kopien der Dateien erhalte, kann ich direkt auf die Tabellen zugreifen. Es macht also wenig Sinn, ein brillantes Passwortverwaltungssystem zu verwenden. Denn wenn jemand auf die Tabelle auf Systemebene zugreifen kann, die die Kennwörter oder Hash-Kennwörter enthält, kann er auch direkt auf die Dateien zugreifen. Warum sich mit dem Knacken von Passwörtern beschäftigen, wenn Sie die Daten bereits haben? Es ist auch nicht so, dass Sie die Daten einfach verschlüsseln können. Jeder Benutzer muss darauf zugreifen können. Die Verschlüsselung auf Benutzerebene funktioniert also nicht so gut.
Aber was Sie wirklich zu fragen scheinen, ist
Sicherheit
Andere haben die Möglichkeit ignoriert, eine sicherere Version zu schreiben, und eine Reihe von Gründen vorgeschlagen. Ich stimme im Allgemeinen zu. Aber es gibt noch eine andere, die noch niemand erwähnt hat. Sie gefährden die Sicherheit Ihrer Datenbank.
In diesem System verfügt jeder Benutzer Ihrer Anwendung über einen Datenbankbenutzer und ein Kennwort. Sicher, es ist ein begrenzter Benutzer, aber es ist immer noch ein Benutzer, der eine Verbindung zur Datenbank herstellen kann. Selbst wenn Sie die Sicherheit auf Zeilenebene verwenden, ermöglichen Sie Endbenutzern weiterhin, Informationen zur Datenbankverbindung zu erhalten. Wenn es jemals einen Exploit gibt, bei dem ein Benutzer sogar Zugriff auf Tabellenebene erhalten kann, haben Sie Ihre Datenbank für Angriffe geöffnet. Einige Exploits gingen darüber hinaus auf den Administratorzugriff über.
In den Schichten der Sicherheitszwiebel ist das normale System:
In diesem System:
Wir haben die gesamte Sicherheitsstufe der Anwendung verloren. Und wir haben freiwillig einen Teil der Datenbankebene aufgegeben. Wir brauchen also nur zwei Exploits:
Wenn wir diese beiden Dinge tun können, haben wir Zugriff auf die Datenbank. Also gehen wir von drei Schichten auf zwei. (Die dritte Schicht im normalen System besteht darin, dass Sie einen gültigen Benutzer benötigen, um eine Verbindung zur Datenbank herzustellen.)
Sie werden viel mit der Verwaltung dieser Konten zu tun haben. Was ist, wenn Sie einen Fehler machen? Anstatt Benutzer X auf bestimmte Zeilen zu beschränken, gewähren Sie allen Zugriff auf eine kritische Tabelle. Solche Dinge werden normalerweise manuell erledigt und es gibt nur wenige davon, so dass sie leicht zu prüfen sind. In Ihrem System können Sie jedoch Tausende oder Millionen oder sogar Milliarden von Benutzerkonten erstellen, von denen jedes seinen eigenen eigenwilligen Zugriff hat.
Skaliert das System der Datenbank auf Millionen oder Milliarden Benutzer? Wenn ja, wie steht es mit der Anzahl der Regeln? Wenn jeder Benutzer hundert oder mehr Regeln darüber aufstellt, auf was er zugreifen kann und was nicht, skaliert das auf eine Milliarde Benutzer? Sie nehmen ein normalerweise kleines System und machen es groß. Das wird nicht unbedingt funktionieren. Während Sie wachsen, können Systembeschränkungen auftreten.
quelle
Was Sie beschreiben, behandelt die Authentifizierung, jedoch nicht die Autorisierung (auf welche Daten der Benutzer zugreifen kann) oder nur im einfachsten Anwendungsfall.
So fahren Sie mit Ihrem Beispiel mit stackexechange fort: Wie würden Sie gelöschte Beiträge nur für Benutzer mit hohen Wiederholungszahlen sichtbar machen? Für Zugriffsregeln benötigen Sie also weiterhin Logik im Code. Anstatt die Zugriffslogik zwischen Datenbankregeln und anwendbaren Zugriffsregeln zu teilen, ziehen es die meisten Entwickler vor, sie alle am selben Ort zu haben.
Sie benötigen auch eine Tabelle zum Speichern der Benutzerinformationen: Ein Benutzer ist nicht nur ein Benutzername + Passwort. Er hat eine E-Mail, einen Ruf und so weiter. Sie benötigen also weiterhin die Benutzertabelle, die Sie sicherstellen müssen, dass sie mit der Datenbankbenutzertabelle synchron ist, sofern Sie darauf zugreifen können.
Mit Ihrer Lösung können Sie einfach eine Kennwortspalte weglassen, die nicht so schwer auszufüllen ist: Es gibt gute Bibliotheken und Dokumentationen zum Umgang mit / Hash-Kennwörtern.
Ein anderer Punkt: Wie würden Sie einen Verbindungspool erstellen? Ich kenne nur jdbc (java <-> db) und Sie müssen einen Benutzernamen + ein Passwort angeben, um eine Verbindung herzustellen, die Sie dann bündeln können.
Ich dachte an einige andere Punkte, deren Umsetzung schwieriger / komplizierter sein wird als auf die etablierte Weise:
quelle
CREATE POLICY deleted_posts_high_rep ON posts FOR SELECT TO baseuser USING ((SELECT rep FROM users WHERE name = current_user()) > 10000)
beantwortet Ihre erste Frage. Ich habe nie gesagt, dass ich keine Benutzertabelle mehr benötige, und die Synchronisierung mit der DB-Benutzertabelle ist etwas schwierig, aber möglich. Der Hauptpunkt der diskutierten Technik ist die Sicherheit. Was den Verbindungspool betrifft, arbeite ich mit OCaml und ich muss sagen, dass ich nicht verstehe, warum ich einen Verbindungspool benötigen würde. Ich verwende derzeit eine Hash-Map, die Cookie-Werte mit 0-ary-Funktionen verknüpft, die Verbindungen zurückgeben :-)Ein weiterer Punkt: Mit vielen [1] Webanwendungen können Sie sich online über die App selbst registrieren und ein Benutzerkonto erstellen. Was bedeutet, dass Ihr anonymer Benutzer (der die geringsten Berechtigungen haben sollte, die man annehmen würde) Rechte haben muss, um Benutzer zu erstellen und Berechtigungen zu erteilen!
OK, es ist möglicherweise möglich, die Berechtigungen einzuschränken und übergeordneten Benutzern mehr Berechtigungsoptionen zu gewähren (ich bin mir jedoch nicht bewusst, dass dies nicht der Fall ist - ist "Gewähren von Berechtigungen" nicht oft ein einzelnes Privileg). Trotzdem bedeutet es, etwas mit Berechtigungen online zu stellen, auf das sich jeder hacken kann. Ich bin mir ziemlich sicher, dass mein DBA mich nicht mögen würde, wenn ich das tun würde :)
Ich weiß, dass dieses Problem auf einer Ebene ohnehin besteht, aber Sie haben Schutzschichten, insbesondere beim Löschen von Daten, wenn Sie der Web-App nicht erlauben, DB-Benutzer zu verwalten.
Dies würde auch die Verwendung gepoolter oder wiederverwendeter DB-Verbindungen verhindern.
[1] Die meisten würde ich sagen, aber keine Zahlen, um dies zu belegen
quelle