Comment gérez-vous la sécurité des bases de données à partir d'une application de bureau?

12

Pendant environ 10 ans, j'ai travaillé sur diverses applications clientes de bureau internes avec des magasins de données SQL Server. J'ai rarement commencé ces projets - la plupart sont des travaux de reprise.

Une chose qui semblait constante partout était qu'il y avait un seul compte utilisateur global SQL Server que cette application utilisait qui lui accordait l'autorisation de la base de données commune, et oui dans certaines situations naïves, elle utilisait le sacompte utilisateur, que j'essayais généralement de corriger lorsque cela était possible .

Vous ne pouvez pas vraiment masquer efficacement ce nom d'utilisateur et ce mot de passe que l'application utilise pour accéder à la base de données. Ils sont généralement stockés dans un iniou configfichier, ou peut - être cuit dans l'exécutable lui - même. Dans tous les cas, ils sont visibles par l'utilisateur s'ils creusent un peu. Dans un cas, nous avons en fait utilisé un configfichier mais l' avons chiffré, mais bien sûr, la clé de chiffrement devait être stockée dans l'exécutable (nous n'étions pas naïfs face aux limites de cela, mais cela a effectivement empêché les gens de fouiner qui étaient assez avertis regarder dans les configfichiers).

Tous ces systèmes avaient un système d'authentification utilisateur intégré à l'application, mais bien sûr, ils étaient tous gérés via l'application elle-même, ce qui signifie que les informations utilisateur étaient stockées dans la base de données. L'application restreignait ce que vous pouviez faire en fonction de votre niveau d'accès, mais c'est tout un sujet de discussion si vous pouvez simplement vous connecter à la base de données et exécuter des requêtes ad hoc.

Je suis intéressé de savoir ce que font les autres systèmes pour contourner ce problème. Voici les options que je connais:

  1. Utilisez le mécanisme de sécurité de SQL Server pour gérer une liste d'utilisateurs et de rôles, et faire en sorte que l'application de bureau ajoute et supprime des utilisateurs via des requêtes T-SQL.
  2. Au lieu de vous connecter directement à la base de données, créez une sorte de service Web qui s'exécute sur le serveur et placez-y la logique d'authentification. Faites que chaque demande fasse une validation de sécurité.

La première option est un peu moche car vous séparez les utilisateurs de la base de données afin que les utilisateurs ne soient plus des entités de première classe et que vous ne puissiez pas les référencer avec des relations de clé étrangère, etc.

Le second semble juste être un problème de performance majeur, et beaucoup de travail supplémentaire, et vous ne pouvez pas utiliser aussi facilement des mappeurs ORM comme NHibernate (je pense).

Est-ce que quelqu'un a de l'expérience avec ça? Les meilleures pratiques?

Éditer

En réfléchissant un peu plus, l'authentification SQL Server peut-elle réellement résoudre ce problème? Par exemple, si votre utilisateur doit être en mesure d'insérer et de mettre à jour des enregistrements de feuille de temps afin que vous puissiez modifier votre feuille de temps, il n'y a aucun moyen que SQL Server puisse interdire l'accès aux autres lignes du tableau de détails de la feuille de temps, ce qui signifie que vous pouvez également lire et écrire les feuilles de temps d' autres personnes.

Scott Whitlock
la source
Sur le thème des reliures; ne pas utiliser ORM comme NHibernate est (je pense) un problème non. Si vous utilisez des services Web à titre d'exemple, vous trouverez de nombreuses façons de lier efficacement vos données à XML.
jasonk
Vous ne devriez pas utiliser votre ORM comme un mappage direct entre les objets métier et les entités de base de données de toute façon, c'est une mauvaise approche qui rend les interfaces fragiles. Envoyez des demandes à une couche de gestion qui obtient des entités de base de données brutes et renvoie uniquement les données requises au client.
gbjbaanb
@gbjbaanb - bien sûr, je vais changer toute l'architecture cet après-midi. :)
Scott Whitlock
Je suppose que vous pourriez attendre que quelqu'un vous pirate avant de le changer, mais du bon côté, vous n'aurez aucun problème à amener votre patron à financer la ré-architecture :-)
gbjbaanb
Vous pouvez empêcher un utilisateur de mettre à jour les enregistrements de quelqu'un d'autre - en utilisant une procédure stockée comme seul moyen de mettre à jour les enregistrements et en utilisant l'utilisateur qui exécute le proc dans le cadre de la requête. Voir CURRENT_USER
gbjbaanb

Réponses:

9

Je crains que l'ajout d'une couche de service Web soit probablement la bonne solution à votre problème.

Séparer le client de l'implémentation de la base de données sous-jacente vous aidera probablement aussi à long terme.

L'ajout d'une couche de service Web ne doit pas nécessairement nuire aux performances ...

En effet, avec une API appropriée, un service Web peut réellement améliorer les performances, en regroupant plusieurs requêtes de base de données dans le réseau local du centre de données, plutôt que d'exiger plusieurs allers-retours sur le WAN.

Et bien sûr, une couche de service Web peut souvent être mise à l'échelle horizontalement et ajouter une mise en cache appropriée à vos requêtes de base de données, peut-être même un mécanisme de notification de changement.

Une couche serveur ajoute une sécurité que vous ne pouvez pas garantir avec les applications s'exécutant sur un client distant. Tout ce qui s'exécute sur un client peut être «piraté» et ne doit en aucun cas être considéré comme fiable. Vous ne devez vraiment mettre la logique de présentation dans le client et héberger quoi que ce soit d'important sur le matériel dont vous avez le contrôle total.

Je ne connais pas vos applications, mais mes applications Web sont naturellement divisées en plusieurs couches, le code de présentation étant séparé de la couche de persistance par au moins un niveau de logique métier qui les sépare. Je trouve que cela rend beaucoup plus facile de raisonner sur mon application, et tellement plus rapide d'ajouter ou de modifier des fonctionnalités. Si les couches sont séparées de toute façon, il est relativement facile de garder la couche de présentation dans le client et le reste sur un serveur sous mon contrôle.

Ainsi, bien que vous puissiez résoudre vos problèmes sans introduire de couche "service Web", au moment où vous aurez écrit toutes les procédures stockées (ou équivalentes) nécessaires pour combler les trous dans l'implémentation de sécurité de base de données standard, vous feriez probablement mieux d'écrire une application côté serveur pour laquelle vous pouvez écrire des tests unitaires appropriés.

Bill Michell
la source
Je reconnais que ce n'est pas nécessairement un goulot d'étranglement en termes de performances, mais cela ajoute certainement une couche supplémentaire à l'architecture, ce qui signifie beaucoup plus de maintenance.
Scott Whitlock
3
Il ajoute une couche, mais pas forcément de maintenance. Considérez qu'avec toute la logique placée dans le service, pas le client, les modifications peuvent être «déployées» sans exiger des utilisateurs qu'ils mettent à jour leurs applications clientes.
GrandmasterB
5

Semblable à la réponse de jmoreno, vous pouvez refuser à un utilisateur l'accès à tout sauf les autorisations EXECUTE sur les procédures stockées, puis profiter du chaînage de la propriété pour que la procédure stockée effectue les opérations requises sur les tables.

Voir ici pour plus de détails https://msdn.microsoft.com/en-us/library/bb669058(v=vs.110).aspx

Lorsque l'utilisateur entre son côté client de nom d'utilisateur / mot de passe, je les stocke et envoie comme paramètres à chaque appel de procédure stockée. Vous pouvez ensuite les vérifier par rapport aux valeurs stockées dans une table avant d'effectuer l'opération souhaitée.

Ce n'est certainement pas le dernier mot en matière de sécurité, mais cela peut être nécessaire si vos PC ont des connexions génériques, limitant votre capacité à utiliser des groupes AD pour les autorisations, ou si vous avez un accès limité à AD lui-même.

James K
la source
2

Une approche consiste à utiliser des groupes AD et des procédures stockées pour limiter ce que l'utilisateur peut faire - par exemple, votre base de données de feuille de temps, pourrait autoriser l'insertion, la mise à jour et la suppression des heures des utilisateurs, mais pas la mise à jour des heures de quelqu'un d'autre. L'ID de l'utilisateur serait fourni par le moteur de base de données, l'utilisateur n'aurait aucun accès direct aux tables de base de données, uniquement aux sp qui exécutaient des requêtes en fonction de leur identifiant de connexion.

Bien sûr, ce n'est pas toujours possible, mais cela peut l'être. La meilleure approche dépendra de vos besoins et de vos ressources.

jmoreno
la source
C'est quelque chose que je n'avais pas envisagé. Je ne suis pas sûr que ce soit un bon ajustement, mais cela fonctionnerait.
Scott Whitlock
1

Ce que vous faites allusion à un «service Web» s'appelle une architecture à plusieurs niveaux . C'est généralement la voie à suivre dans les cas où des problèmes de sécurité ou de configuration sont probables (par exemple, la distribution d'une application dans de nombreux bureaux). Cependant, il ne doit pas nécessairement être basé sur le Web. Beaucoup fonctionnent avec d'autres protocoles.

Vous créez un serveur d'applications pour servir d'intermédiaire entre le client et la base de données (et d'autres ressources). Le serveur d'applications gère l'authentification basée sur votre application et effectue des actions au nom du client. En fait, idéalement, vous ne feriez pas de SQL dans votre client - vous appelez plutôt des méthodes sur le serveur d'applications. Le serveur d'applications gérerait toutes les manipulations de données.

Cette approche présente plusieurs avantages. Vous n'avez pas besoin de configurer les connexions de base de données et les pilotes sur les clients. Vous ne stockez pas les utilisateurs de base de données, les mots de passe et les serveurs. La configuration des clients n'est même pas nécessaire - il suffit de les pointer dans le code vers la bonne URL ou adresse. De plus, avec la «logique» du serveur d'applications, vous n'avez pas à vous répéter lorsque vous développez d'autres applications - le même serveur d'applications peut être réutilisé par différents types de clients.

GrandmasterB
la source
Encore mieux, si (ou quand) quelqu'un pirate vos postes de travail (ou serveur Web dans un équivalent basé sur le Web), l'attaquant peut avoir un accès complet au système d'exploitation, mais il n'a toujours pas accès à la base de données. Et ils ne peuvent donc pas exécuter "select * from users" vers un fichier qu'ils emportent, pirater à leur guise et laisser votre PDG expliquer aux médias pourquoi votre système sécurisé a été compromis. Si vous utilisez également des sprocs sur la base de données qui autorise uniquement l'accès à l'exécution, l'attaquant peut également pirater votre serveur d'applications et il ne peut toujours pas obtenir l'intégralité de votre base de données utilisateur.
gbjbaanb
1

La technologie a un peu changé. Si vous authentifiez chaque utilisateur auprès de la base de données elle-même et utilisez des rôles de base de données, vous pouvez désormais utiliser ce qu'on appelle une vue actualisable pour résoudre ce problème, au moins dans SQL Server.

Voici à quoi pourrait ressembler une vue pouvant être mise à jour pour une table appelée SomeTableoù chaque ligne de cette table est liée à un employé. L'employé doit pouvoir voir les lignes qui lui sont liées et les membres du rôle RH doivent pouvoir voir toutes les lignes, par exemple:

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

Ensuite, vous accordez à tous les utilisateurs des autorisations de lecture (et éventuellement d'écriture) sur la vue ( vwSomeTable) et aucune autorisation sur la table ( SomeTable).

Vous pouvez tester ceci comme ceci:

EXECUTE AS USER = 'Some_Regular_Username'
SELECT * FROM vwSomeTable

... qui ne devraient renvoyer que leurs lignes. Ou:

EXECUTE AS USER = 'Some_HR_Username'
SELECT * FROM vwSomeTable

... qui renverra toutes les lignes. Notez que vous aurez besoin des autorisations d'exécution en tant que (usurpation d'identité) pour effectuer ce test.

Les vues peuvent être mises à jour, donc même l'utilisateur ordinaire peut le faire, tant que la ligne est liée à sa Employeeligne:

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

L'utilisation de l'authentification par certificat est la manière "correcte" d'implémenter un compte SQL partagé. Le but est d'éliminer l'utilisation du mot de passe pour ce genre de chose.

Mise à jour:

Je suppose que j'ai mal compris la question. Je pensais que cela avait à voir avec la recherche d'une alternative à la mise en place d'un nom d'utilisateur et d'un mot de passe db soit dans une configuration d'application, soit sauvegardés dans l'application elle-même.

Vous pouvez éliminer le problème de la gestion des mots de passe dans les applications en utilisant à la place des certificats côté client. Le certificat lui-même ne suffit pas, vous devez disposer d'un système de distribution et de gestion capable d'opérations telles que la révocation du certificat.

Référence: http://en.wikipedia.org/wiki/Public-key_infrastructure

Dietbuddha
la source
Pouvez-vous fournir plus d'informations à ce sujet? On dirait que cela pourrait être orthogonal à l'intention de ma question d'origine, mais c'est intéressant.
Scott Whitlock
0

Construisant une nouvelle solution de sécurité de bureau, nous avons opté pour la solution de service Web que je vais essayer de décrire ci-dessous.

Nous compilons les exécutables des applications de bureau dans un environnement distinct des développeurs. Et calculez un HASH à partir de cet exécutable qui est enregistré dans la base de données.

Un seul service Web qui fournit toutes les informations nécessaires à l'exécution de l'application, le mot de passe de la base de données, les informations sur la chaîne de connexion, les autorisations utilisateur, etc.

nous utilisons une seule connexion DB par application et enregistrons les détails de l'utilisateur dans la base de données dans des variables de session pour pouvoir auditer les enregistrements.

Une DLL gère toutes les communications entre l'application de bureau et le service Web, qui n'est accessible qu'avec une génération de jetons dans la DLL.

Pour pouvoir obtenir le mot de passe de la base de données d'application à partir du service Web, la DLL calcule les appelants DLL HASH lors de l'exécution et passe en paramètre au service Web qui valide le jeton DLL et le temps d'exécution exécutable calculé HASH à celui enregistré lors de son déploiement. (l'application n'est disponible que dans une seule installation partagée en réseau).

De cette façon, nous sommes tombés, c'est une bonne solution au problème de sécurité qui nous préoccupait le plus et connaissons bien quelques défauts de conception. Sont presque en train de terminer cette implémentation et jusqu'à présent, nous sommes satisfaits des résultats.

Edit: vous pouvez remplacer l'idée de hachage en utilisant des signatures numériques et des certificats X.509.

Vitor Arbex
la source
1
Il semble assez évident où se situe le trou de sécurité flagrant. La DLL dont vous parlez se trouve sur le système du client et il n'y a aucun moyen pour votre code serveur de vérifier qu'il parle à une copie légitime de la DLL ou à une copie piratée / malveillante / fausse. Vous venez de créer beaucoup de travail pour vous-même sans ajouter de sécurité supplémentaire, le cas échéant. Tout ce dont une personne malveillante a besoin, c'est du jeton et de l'algorithme, qui sont tous deux dans la DLL pour tous ceux qui veulent regarder.
Scott Whitlock
@ScottWhitlock, oui, je suis d'accord. nous cherchons à brouiller la DLL et le trafic via HTTPS. Nous essayons d’améliorer cela, j’aimerais vraiment avoir des informations sur la façon de l’améliorer. Mais cette solution résout déjà de nombreux problèmes rencontrés par le système actuel, notamment les mots de passe en texte brut stockés dans des fichiers réseau. De plus, le webservice permet la réutilisation de beaucoup de code accessible par n'importe quel langage client que nous utilisons ici, y compris les clients Delphi et Clipper (Harbour)!
Vitor Arbex
Dans votre système, l'utilisateur se connecte et est vraisemblablement authentifié par le service Web. En supposant l'utilisation de HTTPS, n'est-ce pas suffisant? Vous n'avez pas à faire confiance au logiciel client, car vous savez que l'utilisateur est ce qu'il dit être, et vous contrôlez le service Web, alors assurez-vous que le service Web ne distribue que les informations que l'utilisateur donné est autorisé à voir. Même s'ils ont procédé à une ingénierie inverse du client et ont écrit le leur, quels dommages pourraient-ils faire? Seul votre service Web connaît le mot de passe de la base de données, et cela devrait être sûr.
Scott Whitlock