Wie gehen Sie mit der Datenbanksicherheit in einer Desktop-Anwendung um?

12

Seit ungefähr 10 Jahren arbeite ich an verschiedenen internen Desktop-Client-Anwendungen mit SQL Server-Datenspeichern. Selten habe ich diese Projekte gestartet - die meisten sind Übernahmearbeiten.

Eine Sache, die überall konstant schien, war, dass es ein einziges globales SQL Server-Benutzerkonto gab, das von dieser Anwendung verwendet wurde und das die Berechtigung für die gemeinsame Datenbank gewährte, und ja, in einigen naiven Situationen wurde das saBenutzerkonto verwendet, das ich im Allgemeinen zu beheben versuchte, wenn es möglich war .

Sie können diesen Benutzernamen und das Kennwort, mit denen die Anwendung auf die Datenbank zugreift, nicht wirklich effektiv verbergen. Sie werden normalerweise in einer inioder einer configDatei gespeichert oder möglicherweise in die ausführbare Datei selbst eingebrannt. In allen Fällen sind sie für den Benutzer sichtbar, wenn er ein wenig gräbt. In einem Fall haben wir tatsächlich eine configDatei verwendet, diese aber verschlüsselt, aber natürlich musste der Verschlüsselungsschlüssel in der ausführbaren Datei gespeichert werden (wir waren nicht naiv gegenüber den Einschränkungen, aber es hat die Leute effektiv davon abgehalten, sich umzusehen, die geschickt genug waren configDateien anschauen ).

Alle diese Systeme verfügten über ein Benutzerauthentifizierungssystem, das in die Anwendung integriert war. Natürlich wurden sie alle über die Anwendung selbst verwaltet, was bedeutet, dass die Benutzerinformationen in der Datenbank gespeichert wurden. Die Anwendung hat die möglichen Aktionen auf der Grundlage Ihrer Zugriffsebene eingeschränkt. Es ist jedoch problematisch, wenn Sie nur eine Verbindung zur Datenbank herstellen und Ad-hoc-Abfragen ausführen können.

Ich bin gespannt, was andere Systeme tun, um dieses Problem zu umgehen. Ich kenne folgende Optionen:

  1. Verwenden Sie den Sicherheitsmechanismus von SQL Server, um eine Benutzer- und Rollenliste zu verwalten und die Desktopanwendung zu veranlassen, Benutzer über T-SQL-Abfragen hinzuzufügen und zu entfernen.
  2. Erstellen Sie einen Webservice, der auf dem Server ausgeführt wird, und fügen Sie die Authentifizierungslogik dort ein, anstatt sich direkt mit der Datenbank zu verbinden. Führen Sie bei jeder Anforderung eine Sicherheitsüberprüfung durch.

Die erste Option ist etwas hässlich, da Sie Benutzer von der Datenbank trennen, sodass Benutzer keine erstklassigen Entitäten mehr sind und Sie sie nicht mit Fremdschlüsselbeziehungen usw. referenzieren können.

Die zweite scheint nur ein schwerwiegendes Leistungsproblem zu sein und eine Menge zusätzlicher Arbeit. Außerdem können Sie ORM-Mapper wie NHibernate nicht so einfach verwenden (glaube ich).

Hat jemand Erfahrung damit? Empfohlene Vorgehensweise?

Bearbeiten

Kann die SQL Server-Authentifizierung dieses Problem tatsächlich lösen? Zum Beispiel, wenn Ihre Benutzer in der Lage sein müssen , einzusetzen und zu aktualisieren Zeiterfassungs Aufzeichnungen , so dass Sie Ihre Zeiterfassungs bearbeiten können, gibt es keine Möglichkeit , SQL - Server Zugriff auf andere Zeilen in der Zeitenliste Details Tabelle nicht zulassen kann, das heißt , Sie können lesen und schreiben andere Leute auch die Zeiterfassungen.

Scott Whitlock
quelle
Zum Thema Bindungen; ORM nicht wie NHibernate zu verwenden, ist (glaube ich) kein Problem. Wenn Sie als Beispiel Webservices verwenden, finden Sie viele Möglichkeiten, um Ihre Daten effizient an XML zu binden.
Jasonk
Sie sollten Ihr ORM ohnehin nicht als direkte Zuordnung zwischen Geschäftsobjekten und DB-Entitäten verwenden. Dies ist ein schlechter Ansatz, der zu fragilen Schnittstellen führt. Stellen Sie Anforderungen an eine Business-Schicht, die unformatierte DB-Entitäten abruft und nur die erforderlichen Daten an den Client zurückgibt.
gbjbaanb
@gbjbaanb - sicher, ich werde heute Nachmittag die gesamte Architektur ändern. :)
Scott Whitlock
Ich nehme an, du könntest warten, bis dich jemand gehackt hat, bevor du es
änderst
Sie können verhindern, dass ein Benutzer die Datensätze eines anderen Benutzers aktualisiert - indem Sie eine gespeicherte Prozedur als einzige Möglichkeit zum Aktualisieren der Datensätze und den Benutzer verwenden, der den Prozess als Teil der Abfrage ausführt. Siehe CURRENT_USER
gbjbaanb

Antworten:

9

Ich fürchte, das Hinzufügen einer Web-Service-Ebene ist wahrscheinlich die richtige Lösung für Ihr Problem.

Die Trennung des Clients von der zugrunde liegenden Datenbankimplementierung wird Ihnen wahrscheinlich auch langfristig helfen.

Das Hinzufügen eines Webservice-Layers muss nicht unbedingt die Leistung beeinträchtigen ...

In der Tat kann ein Webdienst mit einer geeigneten API die Leistung tatsächlich verbessern, indem mehrere Datenbankabfragen im Rechenzentrums-LAN zusammengefasst werden, anstatt dass mehrere Roundtrips über das WAN erforderlich sind.

Natürlich kann eine Webserviceschicht häufig horizontal skaliert werden und Ihren Datenbankabfragen ein angemessenes Caching hinzufügen, möglicherweise sogar einen Änderungsmechanismus.

Eine Serverschicht fügt Sicherheit hinzu, die Sie möglicherweise bei Apps, die auf einem Remote-Client ausgeführt werden, nicht gewährleisten können. Alles, was auf einem Client läuft, kann "gehackt" werden und sollte in keiner Weise als vertrauenswürdig eingestuft werden. Sie sollten nur Präsentationslogik in den Client einfügen und alles Wichtige auf Hardware hosten, über die Sie die vollständige Kontrolle haben.

Ich kenne Ihre Apps nicht, aber meine Web-Apps sind natürlich in mehrere Ebenen unterteilt, wobei der Präsentationscode durch mindestens eine Ebene der Geschäftslogik von der Persistenz-Ebene getrennt ist, die die beiden voneinander trennt. Ich finde, dies erleichtert das Nachdenken über meine App und das Hinzufügen oder Ändern von Funktionen. Wenn die Ebenen trotzdem getrennt sind, ist es relativ einfach, die Präsentationsebene im Client und den Rest auf einem Server unter meiner Kontrolle zu halten.

Während Sie also Ihre Probleme lösen können, ohne eine "Webservice" -Schicht einzuführen, sollten Sie wahrscheinlich besser schreiben, wenn Sie alle gespeicherten Prozeduren (oder Entsprechungen) geschrieben haben, die zum Ausfüllen der Lücken in der Standardimplementierung der Datenbanksicherheit erforderlich sind Eine serverseitige Anwendung, für die Sie geeignete Komponententests schreiben können.

Bill Michell
quelle
Ich gebe zu, dass es kein Leistungsengpass sein muss, aber es fügt der Architektur sicherlich eine zusätzliche Ebene hinzu, was viel mehr Wartung bedeutet.
Scott Whitlock
3
Es fügt eine Schicht hinzu, aber nicht unbedingt Wartung. Bedenken Sie, dass mit der gesamten Logik des Dienstes und nicht mit dem Client Änderungen durchgeführt werden können, ohne dass Benutzer ihre Clientanwendungen aktualisieren müssen.
GroßmeisterB
5

Ähnlich wie bei der Antwort von jmoreno können Sie einem Benutzer den Zugriff auf alle Elemente außer den EXECUTE-Berechtigungen für gespeicherte Prozeduren verweigern und dann die Verkettung der Eigentumsrechte nutzen, damit die gespeicherte Prozedur die erforderlichen Operationen für die Tabellen ausführt.

Weitere Informationen finden Sie hier https://msdn.microsoft.com/en-us/library/bb669058(v=vs.110).aspx

Wenn der Benutzer seinen Benutzernamen / sein Kennwort clientseitig eingibt, speichere ich sie und sende sie als Parameter an jeden gespeicherten Prozeduraufruf. Sie können sie dann anhand der in einer Tabelle gespeicherten Werte überprüfen, bevor Sie die gewünschte Operation ausführen.

Dies ist definitiv nicht das letzte Wort in Sachen Sicherheit. Dies kann jedoch erforderlich sein, wenn Ihre PCs über allgemeine Anmeldungen verfügen, die Verwendung von AD-Gruppen für Berechtigungen einschränken oder Sie nur eingeschränkten Zugriff auf AD selbst haben.

James K
quelle
2

Ein Ansatz besteht darin, AD-Gruppen und gespeicherte Prozeduren zu verwenden, um die vom Benutzer auszuführenden Aktionen einzuschränken. Beispielsweise kann Ihre Datenbank für Arbeitszeitnachweise das Einfügen, Aktualisieren und Löschen der Arbeitsstunden des Benutzers zulassen, das Aktualisieren der Arbeitsstunden anderer Benutzer jedoch nicht. Die Benutzer-ID wird von der DB-Engine bereitgestellt. Der Benutzer hat keinen direkten Zugriff auf die DB-Tabellen, nur auf SPs, die Abfragen basierend auf der Anmelde-ID ausführen.

Natürlich ist das nicht immer machbar, aber es kann sein. Der beste Ansatz hängt von Ihren Anforderungen und Ressourcen ab.

jmoreno
quelle
Daran hatte ich nicht gedacht. Ich bin mir nicht sicher, ob es gut passt, aber es würde funktionieren.
Scott Whitlock
1

Was Sie als "Web-Service" andeuten, wird als n-Tier-Architektur bezeichnet . Dies ist im Allgemeinen der richtige Weg, wenn Sicherheits- oder Konfigurationsprobleme wahrscheinlich sind (z. B. die Verteilung einer Anwendung auf mehrere Büros). Es muss jedoch nicht webbasiert sein. Viele arbeiten mit anderen Protokollen.

Sie erstellen einen Anwendungsserver als Vermittler zwischen dem Client und der Datenbank (und anderen Ressourcen). Der Anwendungsserver verwaltet Ihre anwendungsbasierte Authentifizierung und führt im Auftrag des Clients Aktionen aus. Im Idealfall würden Sie in Ihrem Client kein SQL ausführen, sondern Methoden auf dem App-Server aufrufen. Der Anwendungsserver würde alle Datenmanipulationen durchführen.

Der Ansatz bietet eine Reihe von Vorteilen. Sie müssen keine Datenbankverbindungen und Treiber auf Clients konfigurieren. Sie speichern keine Datenbankbenutzer, Kennwörter und Server. Die Konfiguration der Clients ist nicht einmal erforderlich - verweisen Sie sie einfach im Code auf die richtige URL oder Adresse. Dank der "Logik" im Anwendungsserver müssen Sie sich bei der Entwicklung anderer Anwendungen nicht wiederholen - derselbe Anwendungsserver kann von verschiedenen Clienttypen wiederverwendet werden.

GroßmeisterB
quelle
Noch besser ist es, wenn (oder wenn) jemand Ihre Desktops (oder Webserver in einem webbasierten Äquivalent) hackt, der Angreifer möglicherweise uneingeschränkten Zugriff auf das Betriebssystem hat, er jedoch weiterhin keinen Zugriff auf die Datenbank hat. Und so können sie dann nicht "select * from users" ausführen, das an eine Datei weitergeleitet wird, die sie entfernen, nach Belieben knacken und Ihren CEO den Medien erklären lassen, warum Ihr sicheres System kompromittiert wurde. Wenn Sie in der Datenbank auch Sprocs verwenden, die nur Ausführungszugriff ermöglichen, kann der Angreifer auch Ihren App-Server hacken und trotzdem nicht die gesamte Benutzerdatenbank abrufen.
gbjbaanb
1

Die Technologie hat sich ein wenig verändert. Wenn Sie jeden Benutzer bei der Datenbank selbst authentifizieren und Datenbankrollen verwenden, können Sie jetzt eine sogenannte aktualisierbare Ansicht verwenden, um dieses Problem zumindest in SQL Server zu beheben.

So könnte eine aktualisierbare Ansicht für eine Tabelle mit dem Namen aussehen, SomeTablebei der jede Zeile in dieser Tabelle mit einem Mitarbeiter verknüpft ist. Der Mitarbeiter sollte in der Lage sein, die mit ihm verknüpften Zeilen anzuzeigen, und Mitglieder der HR-Rolle sollten in der Lage sein, alle Zeilen anzuzeigen. Beispiel:

CREATE VIEW [dbo].[vwSomeTable]
AS
    SELECT SomeTable.*
    FROM SomeTable
        INNER JOIN Employee ON SomeTable.Employee_ID = Employee.Employee_ID
    WHERE Employee.Username = USER_NAME() OR IS_MEMBER('HR_Role')=1

GO

Anschließend erteilen Sie allen Benutzern Leseberechtigungen (und möglicherweise Schreibberechtigungen) für view ( vwSomeTable) und erteilen keine Berechtigungen für die Tabelle ( SomeTable).

Sie können dies folgendermaßen testen:

EXECUTE AS USER = 'Some_Regular_Username'
SELECT * FROM vwSomeTable

... die nur ihre Zeile (n) zurückgeben sollen. Oder:

EXECUTE AS USER = 'Some_HR_Username'
SELECT * FROM vwSomeTable

... was alle Zeilen zurückgibt. Beachten Sie, dass Sie für diesen Test die Berechtigung Ausführen als (Identitätswechsel) benötigen.

Die Ansichten sind aktualisierbar, so dass auch der normale Benutzer dies tun kann, solange die Zeile mit ihrer EmployeeZeile verknüpft ist :

UPDATE vwSomeTable
SET SomeColumn = 5
WHERE SomeTable_ID = 'TheID'
Scott Whitlock
quelle
0

Die Verwendung der zertifikatbasierten Authentifizierung ist die "richtige" Methode zur Implementierung eines gemeinsam genutzten SQL-Kontos. Das Ziel ist es, die Verwendung von Passwörtern für diese Art von Dingen zu eliminieren.

Aktualisieren:

Ich vermute, die Frage wurde falsch verstanden. Ich dachte, dass es mit dem Versuch zu tun hat, eine Alternative zu finden, einen DB-Benutzernamen und ein Kennwort entweder in einer Anwendungskonfiguration oder in der Anwendung selbst zu speichern.

Sie können das Problem der Verwaltung von Kennwörtern in Anwendungen beseitigen, indem Sie stattdessen clientseitige Zertifikate verwenden. Das Zertifikat selbst reicht nicht aus, Sie müssen über ein Vertriebs- und Verwaltungssystem verfügen, das Operationen wie den Widerruf von Zertifikaten ausführen kann.

Referenz: http://en.wikipedia.org/wiki/Public-key_infrastructure

dietbuddha
quelle
Können Sie uns dazu weitere Informationen geben? Klingt so, als ob es orthogonal zur Absicht meiner ursprünglichen Frage wäre, ist aber interessant.
Scott Whitlock
0

Beim Aufbau einer neuen Desktop-Sicherheitslösung haben wir uns für die Webservice-Lösung entschieden, die ich im Folgenden beschreiben möchte.

Wir kompilieren die ausführbaren Dateien der Desktop-Anwendung in einer von den Entwicklern getrennten Umgebung. Berechnen Sie aus dieser ausführbaren Datei einen HASH, der in der Datenbank aufgezeichnet wird.

Ein Webdienst, der alle erforderlichen Informationen für die Ausführung der Anwendung, das DB-Kennwort, die Informationen zur Verbindungszeichenfolge, die Benutzerberechtigungen usw. bereitstellt.

Wir verwenden eine einzelne Datenbankanmeldung pro Anwendung und zeichnen die Benutzerdetails in der Datenbank in Sitzungsvariablen auf, um Aufzeichnungen überwachen zu können.

Eine DLL verwaltet die gesamte Kommunikation von der Desktop-Anwendung zum Web-Service, auf die nur mit einem in die DLL eingebauten Token zugegriffen werden kann.

Um das Anwendungs-DB-Kennwort vom Webdienst abrufen zu können, berechnet die DLL den HASH des DLL-Aufrufers zur Laufzeit und übergibt ihn als Parameter an den Webdienst, der das DLL-Token validiert, und berechnet den HASH der ausführbaren Laufzeit zu dem, der bei der Bereitstellung aufgezeichnet wurde (Die Anwendung ist nur in einer einzelnen Netzwerkinstallation verfügbar.)

Auf diese Weise ist es eine gute Lösung für das Sicherheitsproblem, mit dem wir uns am meisten befasst haben, und wir sind uns einiger Konstruktionsmängel bewusst. Sind fast fertig mit dieser Implementierung und bis jetzt sind wir mit den Ergebnissen zufrieden.

Bearbeiten: Sie können die Hash-Idee durch digitale Signaturen und X.509-Zertifikate ersetzen.

Vitor Arbex
quelle
1
Es scheint ziemlich offensichtlich, wo die Sicherheitslücke ist. Die DLL, von der Sie sprechen, befindet sich auf dem System des Clients, und der Servercode kann nicht überprüfen, ob es sich um eine legitime Kopie der DLL oder eine gehackte, böswillige oder gefälschte handelt. Sie haben gerade viel Arbeit für sich selbst erstellt, ohne viel, wenn überhaupt, zusätzliche Sicherheit hinzuzufügen. Alles, was eine böswillige Person braucht, ist das Token und der Algorithmus, die beide in der DLL für alle enthalten sind, die suchen möchten.
Scott Whitlock
@ScottWhitlock, Ja, ich stimme zu. Wir beschäftigen uns mit der Verschleierung der DLL und dem Datenverkehr über HTTPS. Wir versuchen, das zu verbessern. Ich würde gerne einen Beitrag dazu leisten, wie ich es verbessern kann. Diese Lösung behebt jedoch bereits viele Probleme des aktuellen Systems, einschließlich der in Netzwerkdateien gespeicherten Klartextkennwörter. Der Webservice ermöglicht auch die Wiederverwendung einer Vielzahl von Codes, auf die in allen hier verwendeten Client-Sprachen zugegriffen werden kann, einschließlich Delphi- und Clipper (Harbour) -Clients!
Vitor Arbex
In Ihrem System meldet sich der Benutzer an und wird vermutlich vom Webdienst authentifiziert. Wenn Sie HTTPS verwenden, ist das nicht gut genug? Sie müssen der Client-Software nicht vertrauen, da Sie wissen, dass der Benutzer derjenige ist, für den er sich ausgibt, und Sie den Webdienst steuern. Stellen Sie daher sicher, dass der Webdienst nur Informationen ausgibt, für die der angegebene Benutzer berechtigt ist. Welchen Schaden könnten sie anrichten, selbst wenn sie den Kunden rückentwickeln und selbst schreiben würden? Nur Ihr Webservice kennt das DB-Passwort, und das sollte sicher sein.
Scott Whitlock