Pourquoi stocker les mots de passe des utilisateurs?

10

Je vois parfois des questions demandant comment stocker en toute sécurité les mots de passe des utilisateurs pour une application Web (en utilisant un SGBDR, je ne parle pas de Facebook ou de Twitter). La réponse habituelle est "salez le mot de passe, puis hachez-le avec un algorithme puissant tel que TDES ou SHA512".

Ma question est: en tant qu'utilisateur du SGBDR, pourquoi devrais-je me soucier du stockage des mots de passe, car la plupart des moteurs ont un mécanisme d'authentification intégré.

Par exemple, si un utilisateur X souhaite créer un mot de passe d'utilisateur de compte Y sur mon application Web, comment émettre la requête suivante:

CREATE USER X WITH ENCRYPTED PASSWORD Y IN GROUP baseuser;

Ensuite, dans mon application, l'utilisateur peut ouvrir une connexion à la base de données en utilisant ses informations d'identification et je n'ai pas à me soucier de la gestion des mots de passe.

Je vois plusieurs avantages à cette méthode:

  • Si le SGBDR décide que l'algorithme de chiffrement doit être changé, je n'ai besoin de rien toucher, juste pour appliquer les mises à jour de sécurité;
  • Il m'est facile de gérer les autorisations utilisateurs. Si un utilisateur est promu au rôle d'administrateur, je n'ai qu'à ajouter l'utilisateur au groupe correspondant;
  • Les injections SQL n'ont plus de sens, car je gère les autorisations pour autoriser exactement ce que je veux autoriser à chaque utilisateur de la base de données (par exemple, dans un forum comme SO, ajouter de nouveaux messages, répondre aux messages, commenter et éditer / supprimer ses propres questions / réponses / commentaires);
  • Un compte utilisateur "anonyme" peut être utilisé pour les connexions non authentifiées à mon application;
  • Chaque utilisateur est propriétaire des données qu'il a fournies.

Mais sur pratiquement toutes les questions que je vois à ce sujet, il semble y avoir un consensus général sur le fait que ce n'est pas ainsi que les choses doivent être faites. Ma question est: pourquoi?

Remarque: le troisième point est autorisé par les stratégies de PostgreSQL et les stratégies de sécurité de Microsoft SQL Server. Je me rends compte que ces concepts sont des nouveaux venus, mais de toute façon, maintenant qu'ils sont là, pourquoi la technique que je décris ne devient-elle pas le moyen standard de gérer les comptes des utilisateurs?

Fabian Pijcke
la source
2
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
Paul White 9
Soit dit en passant, la réponse habituelle est fausse. Vous devez saler le mot de passe, puis le hacher avec un algorithme lent tel que bcrypt ou argon2.
Tgr

Réponses:

27

Parce que pour de nombreuses applications, ils ne veulent pas que des comptes d'utilisateurs individuels se connectent à la base de données. Les utilisateurs / mots de passe / droits / autorisations sont tous gérés au niveau de la couche application, et un seul compte de service dédié est utilisé pour se connecter au serveur principal de la base de données.

En tant que DBA, je ne veux pas avoir à gérer, au niveau de la base de données, les 10 000 utilisateurs actifs d'une application Web publique de taille moyenne, ou peut-être les 2 millions et plus d'utilisateurs d'une application soudainement populaire.

Dans un sens très réel, il s'agit d'une différence de philosophie entre les développeurs d'applications et les développeurs de bases de données / DBA.

Beaucoup / la plupart des développeurs d'applications ne voudront pas transférer la responsabilité des principaux aspects de la fonctionnalité de l'application et / ou des règles métier à la couche de base de données. Au lieu de cela, ils voient la base de données comme un outil pour simplement stocker et récupérer des données.

Dans certains cas, cela peut être à courte vue; de nombreux SGBDR ont des fonctionnalités impressionnantes qui pourraient faciliter la vie des développeurs d'applications (sécurité au niveau des lignes, index en colonnes, stockage de flux de fichiers, etc.).

Mais certaines de ces fonctionnalités plus cool ne sont disponibles que dans les versions plus récentes, et les organisations ne sont pas toujours rapides à mettre à niveau les environnements existants (voir ce tableau de 2014 ).

Et dans d'autres cas, la gestion de ces choses au niveau de la couche application est préférée (et pas seulement pour la portabilité de la plate-forme de base de données, je pense franchement que la revendication est exagérée).

BradC
la source
2
Il existe une «guerre sainte» qui consiste à savoir si la logique métier va dans l'application ou dans la base de données. Si vous avez créé une application où toute la logique métier (en particulier la sécurité) se trouve dans la base de données (à l'aide de procédures stockées, de vues, etc.), il peut y avoir un argument pour utiliser les mécanismes de sécurité de la base de données car personne ne peut se connecter directement et contourner votre Sécurité. Je suis tout à fait d'accord pour éviter de «reconstruire» un mécanisme de sécurité (c'est-à-dire login / mot de passe) dans un tableau personnalisé. Pourquoi faire cela quand vous avez déjà la sécurité Active Directory / O365.
Nick.McDermaid
1
@ Nick.McDermaid J'aime m'assurer de bien mélanger la logique métier entre la base de données et l'application pour aider à éliminer le potentiel des futurs développeurs d'avoir la moindre idée de ce qui se passe, cela m'aide également à maintenir la sécurité de mon emploi car personne n'est fou assez pour vouloir le gérer.
Der Kommissar
Jetez un service Web et un serveur d'applications Tomcat là-dedans et vous pourriez travailler pour IBM
Nick.McDermaid
8

La ligne de démarcation devient un peu duveteuse à ce stade, mais je considérerais que les utilisateurs et les autorisations au niveau de la base de données font partie du schéma et ne font pas partie des données, et en général, les applications n'ont pas leur place pour modifier le schéma (il y a, comme toujours, exceptions à cette règle).

Je préfère ne pas donner aux applications les autorisations dont elles ont besoin pour gérer les objets de schéma (connexions, utilisateurs et autorisations) car de nouveaux utilisateurs sont nécessaires et les anciens quittent, car si cette application est piratée, l'attaquant a alors accès à ces autorisations ce qui facilite l'ouverture de la base de données. Dans MS SQL Server, à moins que vous n'utilisiez des bases de données entièrement contenues, les connexions sont des objets de niveau serveur, vous devez donc distribuer des droits au-delà de la base de données d'application unique, ce qui la rend encore plus risquée.

De plus, même si vous avez des comptes d'utilisateurs par application au niveau de votre base de données, vous avez toujours besoin de comptes d'utilisateurs au niveau de l'application pour traiter les demandes non authentifiées - c'est-à-dire si l'application a besoin d'informations de la base de données avant que l'utilisateur de l'application ne s'authentifie avec succès (peut-être pour afficher les informations d'état sur l'écran d'accueil / de connexion?).

De plus, si la portabilité entre les moteurs de base de données est un objectif (peut-être que votre application veut pouvoir fonctionner à la fois sur mysql et sur postgres?), Vos applications devront résumer les fonctions de gestion des utilisateurs / connexions pour chaque moteur car elles ne sont pas standard entre elles - si vous faites cet effort, vous pourriez aussi bien implémenter vous-même les mots de passe et obtenir les options de gestion que vous désirez au lieu d'accepter le jeu de fonctionnalités commun le plus bas que les moteurs offrent.

David Spillett
la source
1
Ok, donc "l'application ne doit pas modifier le schéma" est à mon avis le premier bon point contre la technique que je propose. Cependant, le compte anonyme capable de créer de nouveaux utilisateurs n'a besoin que de pouvoir créer de nouveaux utilisateurs avec l'accès le plus basique. Seuls les administrateurs peuvent promouvoir et supprimer des utilisateurs, ce qui est, je suppose, ce que l'on souhaite dans les applications :-) Les données générales sont visibles pour l'utilisateur anonyme, de sorte que cette connexion peut être utilisée pour le contenu où l'authentification n'est pas nécessaire. La portabilité est également un bon point, mais je pense que les commandes utilisateur font désormais partie de la norme (pas sûr, ce n'était pas le cas il y a des années)
Fabian Pijcke
Soit dit en passant avec ce paramètre, si un pirate a accès à la base de données en tant qu'utilisateur anonyme, il pourra créer autant d'utilisateurs qu'il le souhaite, mais ce n'est pas un problème de sécurité, il pourrait aussi sûrement gonfler la base de données en utilisant l'un des les comptes créés, ce serait ennuyeux mais encore une fois pas de problème de sécurité (et il pourrait le faire en utilisant l'interface standard aussi de toute façon, ce serait bien plus lent cependant: p)
Fabian Pijcke
3
Je suis d'accord que du point de vue de la sécurité, les utilisateurs au niveau de la base de données seraient mieux. Cependant, cela est fondamentalement impossible à gérer avec, par exemple, des boutiques en ligne où vous pourriez avoir 50 millions d'utilisateurs enregistrés. Chacun devrait être un utilisateur de base de données. Le plus: cela ne fonctionne généralement pas bien avec les applications Web utilisant un pool de connexions.
a_horse_with_no_name
6

Reformuler la question

Pourquoi stocker les mots de passe des utilisateurs?

La réponse la plus simple est que vous devez le faire. Vous conservez toujours les mots de passe dans votre méthode alternative. C'est juste que vous utilisez le système intégré de la base de données pour gérer le stockage. Votre méthode est donc aussi bonne que celle de votre base de données. C'est peut-être encore mieux que ce que vous pourriez faire autrement, mais cela n'évite pas le stockage. Cela évite vraiment de coder le stockage.

Cela pourrait aussi ne pas être mieux. Si je compromets une base de données et obtiens des copies des fichiers, je peux accéder directement aux tables. Il n'y a donc aucun intérêt à utiliser un système de gestion de mots de passe génial. Parce que si quelqu'un peut accéder à la table de niveau système contenant les mots de passe ou les mots de passe hachés, il peut également accéder directement aux fichiers. Pourquoi s'embêter à casser des mots de passe alors que vous avez déjà les données? Ce n'est pas comme si vous pouviez chiffrer les données facilement non plus. Chaque utilisateur doit pouvoir y accéder. Le chiffrement au niveau utilisateur ne fonctionnera donc pas aussi bien.

Mais ce que vous semblez vraiment demander, c'est

Pourquoi utiliser un schéma d'authentification au niveau de l'application alors que la base de données en a déjà un?

Sécurité

Ignorant la possibilité que vous puissiez écrire une version plus sécurisée, d'autres ont suggéré un certain nombre de raisons. Je suis généralement d'accord. Mais il y en a un autre que personne n'a encore mentionné. Vous compromettez la sécurité de votre base de données.

Dans ce système, chaque utilisateur de votre application possède un utilisateur de base de données et un mot de passe. Bien sûr, c'est un utilisateur limité, mais c'est toujours un utilisateur qui peut se connecter à la base de données. Même si vous utilisez la sécurité au niveau des lignes, vous autorisez toujours les utilisateurs finaux à connaître les informations de connexion à la base de données. S'il y a un exploit où un utilisateur peut obtenir un accès égal au niveau de la table, vous avez ouvert votre base de données pour attaquer. Et certains exploits sont allés au-delà de cet accès administrateur.

Dans les couches de l'oignon de sécurité, le système normal est:

  • Base de données, qui autorise uniquement les connexions à partir de certaines machines.
  • Base de données, autorise uniquement les connexions en tant que certaines combinaisons utilisateur / mot de passe.
  • Serveurs avec des autorisations de base de données qui autorisent les connexions à partir d'applications.
  • Les applications sont exécutées sur le serveur.
  • Les applications ont des informations de connexion à la base de données avec des privilèges limités.
  • Les applications authentifient les utilisateurs avant de leur permettre de modifier la base de données (sauf éventuellement pour créer de nouveaux comptes).

Dans ce système:

  • Les utilisateurs finaux connaissent les combinaisons utilisateur / mot de passe qui fonctionneront sur la base de données, certes avec des privilèges très faibles.
  • Il suffit de comprendre un serveur ou de faire semblant d'être un serveur autorisé.

Nous avons perdu tout le niveau de sécurité de l'application. Et nous avons volontairement abandonné une partie de la couche de base de données. Nous n'avons donc besoin que de deux exploits:

  1. Usurper ou compromettre un serveur autorisé.
  2. Augmentez l'accès du compte à privilège limité.

Si nous pouvons faire ces deux choses, nous avons accès à la base de données. On passe donc de trois couches à deux. (La troisième couche du système normal est que vous avez besoin d'un utilisateur valide pour vous connecter à la base de données.)

Vous allez faire beaucoup de gestion de ces comptes. Et si vous vous trompez? Au lieu de limiter l'utilisateur X à certaines lignes seulement, vous leur donnez tous accès à une table critique. Ce genre de choses se fait normalement manuellement et il n'y en a que quelques-unes, donc elles sont faciles à auditer. Mais dans votre système, vous pourriez créer des milliers, voire des millions, voire des milliards de comptes d'utilisateurs, chacun avec son propre accès idiosyncrasique.

D'ailleurs, le système de la base de données s'adapte-t-il à des millions ou des milliards d'utilisateurs? Si c'est le cas, qu'en est-il du nombre de règles? Si chaque utilisateur adopte une centaine de règles ou plus sur ce qu'il peut et ne peut pas accéder, cela peut-il atteindre un milliard d'utilisateurs? Vous prenez un système normalement à petite échelle et vous le faites à grande échelle. Cela ne fonctionnera pas nécessairement. Vous pouvez rencontrer des limitations du système à mesure que vous grandissez.

mdfst13
la source
5

Ce que vous décrivez gérera l'authentification, mais pas l'autorisation (quelles données l'utilisateur peut accéder) ou uniquement dans le cas d'utilisation le plus simple.

Pour continuer sur votre exemple avec stackexechange: Comment feriez-vous pour que le message supprimé ne soit visible que pour les utilisateurs de haut niveau? Donc, pour les règles d'accès, vous aurez toujours besoin de logique dans le code. Au lieu de partager la logique d'accès entre les règles de base de données et les règles d'accès applicatives, la plupart des développeurs préfèrent les avoir toutes au même endroit.

Vous aurez également besoin d'une table pour stocker les informations utilisateur: un utilisateur n'est pas seulement un nom d'utilisateur + mot de passe. Il a un e-mail, une réputation, etc. Vous avez donc toujours besoin de la table utilisateur, dont vous devez vous assurer qu'elle est synchronisée avec la table utilisateur de la base de données, à condition que vous puissiez y accéder.

Avec votre solution, vous pouvez simplement omettre une colonne de mot de passe, ce qui n'est pas si difficile à remplir: il existe de bonnes bibliothèques et une bonne documentation sur la façon de gérer / hacher les mots de passe.

Autre point: comment créer un pool de connexions? Je ne connais que jdbc (java <-> db), et vous devez fournir un nom d'utilisateur + mot de passe pour obtenir une connexion, que vous pourrez ensuite regrouper.

J'ai pensé à d'autres points qui seront plus difficiles / plus compliqués à mettre en œuvre qu'avec la méthode établie:

  • gestion de la récupération des mots de passe
  • 2 ans après la mise en œuvre initiale, votre chef de produit vous demande d'ajouter la prise en charge du schéma oauth ou d'autoriser l'authentification à double facteur
Thierry
la source
Quelque chose comme CREATE POLICY deleted_posts_high_rep ON posts FOR SELECT TO baseuser USING ((SELECT rep FROM users WHERE name = current_user()) > 10000)répond à votre première question. Je n'ai jamais dit que je n'avais plus besoin d'une table d'utilisateurs, et assurer la synchronisation avec la table d'utilisateurs db est quelque peu délicat mais possible. Le point principal de la technique discutée est la sécurité. Quant au pool de connexions, je travaille avec OCaml et je dois dire que je ne comprends pas pourquoi j'aurais besoin d'un pool de connexions. J'utilise actuellement une carte de hachage associant les valeurs des cookies aux fonctions 0-aire renvoyant des connexions :-)
Fabian Pijcke
5
Le pool de connexions est implémenté pour améliorer les performances: avec eux, vous n'avez pas besoin d'établir une connexion pour chaque demande utilisateur (vous économisez donc cpu / io / latence lors de la création du lien tcp + toute la connexion et l'échange d'authentification avec la base de données). Quant à la définition de la politique: votre base de données vérifiera constamment les droits d'accès à chaque accès aux données, même si vous les avez déjà vérifiées une fois. De même, «accès refusé ou interdit» n'est pas la même chose que «OK, aucun résultat». Pas sûr que les gars de la sécurité préfèrent la version OK.
Thierry
3
Fabian, la mise en commun des connexions est fondamentale à toute sorte d'échelle, c'est vraiment une valeur par défaut que vous n'envisageriez même pas de ne pas utiliser. Voici quelques points de repère juste pour vous donner une idée de son importance: augmentation des performances de 600x avec le regroupement de connexions ( vladmihalcea.com/2014/04/17/the-anatomy-of-connection- Covoiturage ) et augmentation de plus de 4000x des performances avec mise en commun des connexions ( progress.com/tutorials/jdbc/… ). C'est une différence de plusieurs ordres de grandeur, ce n'est pas "agréable à avoir", les applications s'arrêteraient sans cela.
Ivan McA
1
Des chiffres intéressants. Et en effet, je n'ai jamais vu une application n'utilisant pas de pools de connexions. Mais je ne les connaissais pas (et je ne m'attendais pas) à ce qu'ils accélèrent autant. L'autre aspect que vous obtenez avec le pool de connexions est le contrôle des ressources: grâce à eux, une augmentation considérable du nombre de clients essayant de se connecter simultanément rendra votre application lente, mais votre base de données ne sera pas autant impactée (si le pool est bien configuré) .
Thierry
Ok, je viens de chercher plus d'informations sur les pools de connexions, et je conviens que c'est un point très valable dès que le site Web doit gérer plus de cent connexions par seconde, ce qui n'est pas si élevé. Il semble que chaque connexion dans PostgreSQL consomme environ 10 Mo de RAM! Je n'ai jamais pensé que c'était autant.
Fabian Pijcke
1

Autre point: de nombreuses [1] applications Web vous permettent de vous inscrire et de créer un compte utilisateur en ligne via l'application elle-même. Cela signifie que votre utilisateur anonyme (qui devrait avoir le moins de privilèges que l'on pourrait supposer) doit avoir le droit de créer des utilisateurs et d'accorder des privilèges!

OK, il peut être possible de limiter les privilèges qu'il pourrait accorder, et de donner aux utilisateurs de niveau supérieur plus d'options d'octroi (je ne suis pas conscient que c'est le cas - n'est-ce pas "accorder des privilèges" un seul privilège souvent). Mais encore, cela signifie mettre en ligne quelque chose avec des privilèges de subvention pour que tout le monde puisse pirater. Je suis sûr que mon DBA ne m'aimerait pas si je faisais ça :)

Je sais qu'à un certain niveau, ce problème existe de toute façon, mais vous avez des couches de défense, en particulier pour supprimer des données, si vous ne permettez pas à l'application Web de gérer les utilisateurs de la base de données.

En outre, cela empêcherait toute utilisation de connexions DB regroupées ou réutilisées.

[1] La plupart je dirais, mais pas les chiffres pour le confirmer

Adam
la source