web-dev-qa-db-fra.com

Y a-t-il une raison de ne pas passer directement du Javascript côté client à une base de données?

Duplicata possible:
Écriture d'applications Web "sans serveur"

Donc, disons que je vais construire un clone Stack Exchange et je décide d'utiliser quelque chose comme CouchDB comme magasin principal. Si j'utilise leur authentification intégrée et leur autorisation au niveau de la base de données, y a-t-il une raison pour ne pas autoriser le Javascript côté client à écrire directement sur le serveur CouchDB accessible au public? Comme il s'agit essentiellement d'une application CRUD et que la logique métier consiste à "Seul l'auteur peut modifier son message", je ne vois pas vraiment le besoin d'avoir une couche entre les éléments côté client et la base de données. J'utiliserais simplement la validation du côté CouchDB pour m'assurer que quelqu'un ne place pas de données inutiles et que les autorisations sont correctement définies afin que les utilisateurs ne puissent lire que leurs propres données _user. Le rendu serait effectué côté client par quelque chose comme AngularJS. En substance, vous pourriez simplement avoir un serveur CouchDB et un tas de pages "statiques" et vous êtes prêt à partir. Vous n'auriez besoin d'aucune sorte de traitement côté serveur, juste quelque chose qui pourrait servir les pages HTML.

Ouvrir ma base de données au monde semble faux, mais dans ce scénario, je ne vois pas pourquoi tant que les autorisations sont correctement définies. Cela va à l'encontre de mon instinct de développeur Web, mais je ne vois pas de bonne raison. Alors, pourquoi est-ce une mauvaise idée?

EDIT: Il semble qu'il y ait une discussion similaire ici: Écriture d'applications Web "sans serveur"

EDIT: Super discussion jusqu'à présent, et j'apprécie les commentaires de tout le monde! Je pense que je devrais ajouter quelques hypothèses génériques au lieu d'appeler CouchDB et AngularJS spécifiquement. Supposons donc que:

  • La base de données peut authentifier les utilisateurs directement depuis son magasin caché
  • Toutes les communications de base de données se feraient via SSL
  • La validation des données peut (mais ne devrait peut-être pas?) Être gérée par la base de données
  • La seule autorisation dont nous nous soucions autre que les fonctions d'administration est que quelqu'un ne soit autorisé à modifier son propre message
  • Nous sommes parfaitement d'accord pour que tout le monde puisse lire toutes les données (SAUF les enregistrements d'utilisateurs qui peuvent contenir des hachages de mot de passe)
  • Les fonctions administratives seraient limitées par l'autorisation de la base de données
  • Personne ne peut s'ajouter à un rôle d'administrateur
  • La base de données est relativement facile à mettre à l'échelle
  • Il y a peu ou pas de véritable logique commerciale; c'est une application CRUD de base
63
Chris Smith

Faire comme vous le suggérez crée un couplage (er) étroit entre votre langue côté client et votre base de données.

Cela peut être correct - il y a moins de code à écrire et à maintenir, et en théorie, le débogage pourrait/devrait aller un peu plus vite.

En revanche, cela rend d'autres aspects plus difficiles. Si/quand vous devez changer l'une de ces technologies, vous aurez plus de mal à cause du couplage étroit entre elles.

Se protéger contre les attaques sera (assez) un peu plus difficile. Vous supposez que le client présentera toujours des demandes bien formatées à la base de données. Cela suppose que personne ne piratera jamais le code côté client pour insérer des instructions malveillantes. En d'autres termes, ils "emprunteront" vos mécanismes d'authentification et remplaceront le code client normal par le leur.

Je ne le recommanderais pas, et beaucoup vous diraient avec véhémence de ne pas le faire. Mais cela peut être fait.

48
user53019

Ce n'est probablement pas une bonne idée. Et la première et la plus importante raison que je puisse donner est que n serveur de base de données n'est pas conçu pour être un serveur Web public. Au contraire, la sagesse conventionnelle dit que vous devez cacher votre base de données derrière un pare-feu.

Si vous avez besoin de preuves à l'appui, il y a beaucoup de préoccupations - pas toutes insurmontables, mais auxquelles il faut réfléchir. Dans aucun ordre particulier, voici quelques-uns:

  • Il ne peut pas effectuer de nettoyage des requêtes, car vous lui envoyez directement les requêtes .
  • Les autorisations de base de données ont tendance à fonctionner différemment des autorisations de serveur Web et d'application. Les serveurs Web et les frameworks d'application ne démarrent avec rien et vous devez créer et exposer explicitement des ressources, des points de terminaison et des actions individuels. Les bases de données, en revanche, vous demandent d'accorder des rôles à un niveau élevé.
  • Il n'est probablement pas bien optimisé pour supporter la charge de travail d'un serveur Web; vous ne pouvez pas bénéficier de la mise en commun des connexions.
  • Les serveurs Web les plus populaires ont été divisés en beaucoup . Et ils ont reçu beaucoup de correctifs de sécurité. Votre SGBD a été essentiellement conçu pour se cacher derrière un pare-feu, il n'a donc probablement pas été testé par même une fraction d'un pour cent des menaces potentielles auxquelles il sera confronté sur le Web public.
  • Vous devez utiliser le langage de requête de la base de données pour protéger les données privées. En fonction de votre SGBD, cela peut être difficile.
  • Vous devez utiliser le langage de requête de la base de données pour filtrer les grands ensembles de données - quelque chose que vous pourriez vous efforcer de faire de toute façon; mais quelque chose qui peut devenir contraignant pour des règles commerciales plus compliquées.
  • Prise en charge limitée ou inexistante des bibliothèques tierces.
  • Support communautaire très limité (potentiellement nul) pour de nombreux problèmes que vous rencontrerez.

... Et je suis sûr qu'il y a d'autres préoccupations. Et je suis sûr qu'il existe une solution à la plupart - sinon à toutes ces préoccupations. Mais il y a une liste pour commencer!

36
svidgen

La meilleure raison que j'imagine est: parce que cette méthode n'est pas directement prise en charge ou recommandée par les parties impliquées.

Les fournisseurs de navigateurs, les normes EcmaScript, les développeurs de systèmes de base de données, les sociétés d'équipement de réseau, les architectes d'hébergement/d'infrastructure et les spécialistes de la sécurité ne prennent pas activement en charge (ou peut-être même envisagent) votre cas d'utilisation proposé. Il s'agit d'un problème, car la méthode que vous proposez nécessite que toutes ces entités - et plus - fonctionnent correctement pour votre application, même si aucun des systèmes impliqués n'a été conçu pour prendre en charge cela.

Je ne dis pas que ce n'est pas possible. Je dis simplement que cela ressemble moins à "réinventer la roue" et plus à réinventer l'interaction client-serveur basée sur un navigateur.

Au mieux, vous ferez une tonne de travail pour faire fonctionner les systèmes au niveau le plus basique possible. Les bases de données populaires modernes ne sont pas RESTful ou conçues pour fonctionner sur HTTP, vous allez donc créer vos propres pilotes client WebSocket (je présume).

Même si tout fonctionne techniquement, vous abandonnerez bon nombre des fonctionnalités les plus puissantes des architectures modernes. Vous n'aurez aucune défense en profondeur - tout le monde peut facilement se connecter directement à la cible principale de la plupart des tentatives de piratage de sites Web. Mais le scénario que vous proposez est bien, bien pire que cela.

Le modèle proposé ne fait pas qu'exposer le serveur - il expose des chaînes de connexion valides. Les attaquants ne peuvent pas simplement envoyer une requête ping au serveur - ils peuvent se connecter activement et alimenter ses commandes. Même si vous pouvez limiter l'accès aux données, je ne connais pas suffisamment d'outils dans les systèmes SGBD pour se protéger des scénarios de déni de service et de leurs semblables. Lorsque vous travaillez dans des versions améliorées de SQL, comme TSQL, il est souvent trivialement facile de produire des bombes qui s'exécutent efficacement à l'infini (quelques jointures illimitées pour produire un produit cartésien et vous aurez un SELECT qui fonctionnera pour toujours, effectuant un travail lourd) . J'imagine que vous auriez besoin de désactiver la plupart des fonctionnalités de SQL, même en éliminant les requêtes SELECT de base avec JOIN et peut-être en autorisant uniquement les procédures stockées? Je ne sais même pas si tu peux faire ça, on ne m'a jamais demandé d'essayer. Ça ne sonne pas bien.

L'évolutivité de la base de données a également tendance à être l'un des problèmes les plus difficiles à travailler à grande échelle, tandis que la mise à l'échelle de plusieurs serveurs HTTP - en particulier avec des pages statiques ou mises en cache - est l'une des parties les plus faciles. Votre proposition fait travailler la base de données en étant responsable de 100% des activités côté serveur. C'est un défaut de tueur à lui tout seul. Ce que vous gagnez en déplaçant du travail sur le client, vous le perdez en déplaçant plus de travail sur la base de données.

Enfin, je voudrais simplement souligner que le cœur de ce que vous proposez n'est pas nouveau, mais remonte en fait à des décennies. Ce modèle est appelé le modèle de "base de données fat", qui a essentiellement déplacé la plupart des logiques côté serveur dans la base de données comme vous le proposez. Il y a de nombreuses raisons pour lesquelles ce modèle a été abandonné sur Internet de masse, et il serait probablement instructif d'examiner plus en détail cette histoire vous-même. Notez également que même alors, il était peu envisagé que des utilisateurs totalement non fiables puissent se connecter au système et exécuter des commandes, car l'accès serait toujours contrôlé pour sélectionner des utilisateurs internes (connus) qui n'étaient pas censés attaquer le système en permanence.

Le fait est que vous aurez toujours besoin d'un serveur HTTP pour servir les fichiers, car les systèmes de base de données ne le font tout simplement pas. Dans le même temps, tout ce que vous proposez peut être obtenu en utilisant un modèle de serveur léger (comme avec Nodejs) pour exposer une interface RESTful à votre base de données. Ceci est populaire pour une raison: il fonctionne, garde la base de données cachée derrière des couches de protection, est extrêmement évolutif et vous permet néanmoins de construire votre base de données aussi épaisse ou aussi fine que vous le souhaitez.

16
BrianH

Comme il s'agit essentiellement d'une application CRUD et que la logique métier consiste à "Seul l'auteur peut modifier son message", je ne vois pas vraiment le besoin d'avoir une couche entre les éléments côté client et la base de données. J'utiliserais simplement la validation du côté CouchDB pour m'assurer que quelqu'un ne place pas de données inutiles et que les autorisations sont correctement définies afin que les utilisateurs ne puissent lire que leurs propres données _user.

Eh bien, placer votre autorisation (les problèmes de sécurité) et la validation logique loin de la base de données permet de séparer les problèmes dans votre système logiciel. Ainsi, vous pouvez tester, maintenir, mettre à l'échelle et réutiliser vos blocs de code logique avec moins de risques de freiner la fonctionnalité du système.

Fournir la capacité pour l'entrée client de communiquer directement avec la base de données est très important potentiel de bousiller les données.

Cela signifie également qu'éviter/supprimer couplage étroit rend votre système logiciel plus maintenable et SOLIDE.

8
Yusubov

Laisser l'utilisateur interagir directement avec la base de données me semble vraiment dangereux.

Le mécanisme d'authentification de CouchDB est-il vraiment si sophistiqué que vous pouvez isoler l'accès en lecture et en écriture d'un utilisateur uniquement aux données qu'il est censé lire et écrire (nous parlons d'un accès par document, peut-être même par champ de document) privilèges ici)? Qu'en est-il des données "communales" partagées par plusieurs utilisateurs? Cela n'existe-t-il pas du tout dans la conception de votre application?

Voulez-vous vraiment que l'utilisateur puisse modifier ses données de quelque manière que ce soit? Qu'en est-il des injections XSS, par exemple? Ne serait-il pas préférable d'avoir une couche serveur pour filtrer celles-ci avant qu'elles n'entrent dans la base de données?

6
Philipp

Vous avez plusieurs raisons, mais en voici une autre: la pérennité. Tôt ou tard, au fur et à mesure que votre application évolue, vous serez confronté à des exigences qui ne peuvent pas être facilement ou en toute sécurité réalisées dans JS côté client ou en tant que procédure stockée dans votre base de données.

Par exemple, on vous dit que toutes les nouvelles inscriptions doivent avoir une vérification CAPTCHA pour être valides. Ce serait vraiment assez facile avec à peu près n'importe quel cadre d'application Web moderne. Tapez simplement un reCAPTCHA sur le formulaire d'inscription, transmettez le jeton de réponse de reCAPTCHA au backend et ajoutez quelques lignes de code à votre backend pour vérifier la validité du token avec l'API de Google (ou mieux encore, utilisez un bibliothèque quelqu'un d'autre a écrit pour le faire pour vous).

Si vous utilisez un système à deux niveaux et que vous comptez sur la base de données pour toute votre logique côté serveur, comment allez-vous vérifier le jeton? Oui, je suppose qu'il pourrait être théoriquement possible, en fonction du SGBD, d'écrire une procédure stockée qui appelle en quelque sorte un Shell et invoque curl avec les arguments appropriés. C'est aussi presque certainement une horrible idée: le filtrage des entrées et la protection contre les failles de sécurité seraient terribles; vous auriez un désordre avec la gestion des erreurs et les délais; et vous devrez analyser la réponse vous-même. Sans oublier qu'un SGBD n'est pas prévu pour cela, il n'y a donc aucune raison de penser que les performances, la stabilité, la sécurité des threads, etc. ne seront pas des problèmes. Voir, par exemple, ce fil , qui traite de certains de ces problèmes pour Postgres.

Et ce ne sont que les problèmes liés à l'ajout d'un simple CAPTCHA à un formulaire. Qu'allez-vous faire si vous souhaitez ajouter SMS vérification, ou un travail d'arrière-plan qui envoie un e-mail aux utilisateurs inactifs pour leur rappeler votre application, ou ajouter une fonction de téléchargement de fichiers afin que les gens puissent définir un profil image? Peut-être que vous décidez que votre application devrait avoir des tests automatisés un jour? Ou que vous souhaitez suivre les modifications de vos procédures dans un système de contrôle de version? Il existe de nombreuses bibliothèques et outils pour la plupart des langages utiles pour gérer la plupart de ces tâches pour vous, mais peu ou pas seront disponibles pour votre SGBD, car il n'est pas destiné à le faire.

Finalement, vous voudrez faire quelque chose que vous ne pouvez pas raisonnablement faire directement dans votre SGBD, puis vous serez bloqué. Parce que vous aurez construit l'intégralité de votre application dans votre SGBD, vous n'aurez pas d'autre alternative que d'obtenir un serveur Web et de commencer à reconstruire des morceaux dans une autre langue, juste pour ajouter une fonctionnalité simple.

Et ce serait vraiment dommage, car nous avons déjà un nom pour l'endroit où vous mettez votre logique d'application, et cela s'appelle "le code source de votre application" plutôt que "procédures stockées de base de données" pour une raison.

6
Zach Lipton

Si vos contrôles de sécurité et votre logique métier sont contenus dans votre javascript côté client, ils peuvent être remplacés par un utilisateur malveillant. Vous pouvez également utiliser un Technologie côté serveur basée sur JavaScript (comme Node.JS ) pour gérer la validation, l'autorisation, etc.

5
Michael Brown

Toute contrainte métier que vous souhaiterez peut-être garantir doit être validée côté serveur. Même si vous contrôlez l'accès des utilisateurs, quelqu'un peut envoyer des données non valides.

En suivant votre exemple de clone stackoverflow:

  • Comment empêcheriez-vous de toute façon la modification des questions "fermées" sur le site?
  • Comment empêcheriez-vous les gens de supprimer des commentaires?
  • Comment empêcheriez-vous les gens de simuler des dates de commentaires?
  • Comment empêcheriez-vous les gens de voter 50 fois le même message?
  • Il y a probablement beaucoup plus d'exemples si vous creusez un peu plus.

N'importe qui peut manipuler le code côté client et violer complètement l'intégrité des données (même s'il est limité à certains objets, comme leurs propres publications).

2
Jbm

Modifier la page dans firebug et à un moment donné mettre une ligne similaire à ceci:

ExecDbCommand("DROP TABLE Users")

Exécuter.

Éditer:

La question concernait en fait CounchDB, donc pas de sql à exécuter ici. Pourtant, l'idée est la même. Je suppose que toute application non triviale dépend des données pour respecter certaines règles de cohérence qui sont vérifiées/appliquées par le code de l'application. Un utilisateur malveillant peut modifier le code client pour enregistrer les données sous une forme qui viole vos règles métier et peut provoquer des ravages dans votre application.

Si votre site considère que tous les états de données possibles sont valides d'un point de vue commercial, suivez cette voie, mais si ce n'est pas le cas (probable), vous voudriez avoir la garantie que toutes les données qui sont stockées sont générées par - votre code et selon vos règles.

1
AZ01

Vieille question, je sais, mais je voulais répondre car mon expérience est assez différente des autres réponses.

J'ai passé de nombreuses années à écrire des applications collaboratives en temps réel. L'approche générale de ces applications consiste à répliquer les données localement et à synchroniser les modifications avec les pairs le plus rapidement possible. Toutes les opérations sur les données sont locales, donc tout le stockage de données, l'accès aux données, la logique métier et l'interface utilisateur sont des couches sont locales. Le mouvement "offline first" ( http://offlinefirst.org/ ) a adopté cette approche pour créer des applications web hors ligne et peut avoir des ressources pertinentes. Ces types de cas d'utilisation exigent non seulement que vous ouvriez votre couche d'accès aux données aux clients, mais aussi le stockage de données! Je sais je sais. Semble fou, non?

Les préoccupations pour de telles applications hors ligne sont similaires à ce que vous avez demandé, un seul niveau supprimé. Cela me semble pertinent. Étant donné que vous ouvrez l'accès direct aux données aux clients, la question devient, comment pouvez-vous limiter les effets d'un utilisateur malveillant? Eh bien, il y a beaucoup de stratégies, mais elles ne sont pas évidentes si vous venez d'un contexte de développement plus traditionnel.

La première idée fausse est que l'exposition de la base de données signifie l'exposition de toutes les données. Prenez CouchDB par exemple; les bases de données de CouchDB sont légères, vous n’auriez donc pas une seconde pensée à créer des centaines de milliers de bases de données distinctes sur un serveur. Les utilisateurs ne peuvent accéder qu'aux bases de données auxquelles ils sont autorisés à accéder en tant que lecteur ou écrivain (sans parler des fonctionnalités de validation et quoi de CouchDB), de sorte qu'ils ne peuvent accéder qu'à un sous-ensemble des données.

La deuxième idée fausse est qu'un utilisateur cherchant des données est un problème! Si les utilisateurs reçoivent une réplique d'une base de données, ils peuvent utiliser tout ce qu'ils veulent sans affecter les autres utilisateurs. Mais, vous devez valider leurs modifications avant de répliquer leurs données dans le magasin "central". Pensez à Git - les utilisateurs peuvent faire ce qu'ils veulent dans les branches, les fourches et les référentiels locaux sans affecter la branche principale. La fusion avec le maître implique beaucoup de cérémonie et ne se fait pas à l'aveuglette.

Je construis actuellement un système utilisant CouchDB où les utilisateurs doivent collaborer sur les données pour créer un ensemble de données qui est ensuite "publié" via un flux de travail QA/QC. La collaboration est effectuée sur une réplique des données (nous appelons cela une base de données intermédiaire ou de travail), et une fois terminée, une personne responsable effectue l'AQ/QC sur les données et ce n'est qu'après qu'elles sont répliquées dans le référentiel principal.

De nombreux avantages en découlent qui sont difficiles à obtenir dans d'autres systèmes - comme le contrôle de version, la réplication et la collaboration (laissez le travail hors ligne!) Pour les applications CRUD à trois niveaux traditionnelles est super difficile.

Mon conseil - si votre application est "traditionnelle", faites-la de façon traditionnelle. Si l'une des choses que j'ai mentionnées ci-dessus (bien qu'il y en ait beaucoup plus ...) s'applique à vous, alors envisagez des architectures alternatives et préparez-vous à penser latéralement.

1
Daniel Paull

Je pense que, compte tenu de toutes vos hypothèses, il est possible de passer directement du client à la base de données. Cependant, il est raisonnable de vérifier si vos hypothèses sont valides et sont susceptibles de le rester à l'avenir.

Je craindrais qu'à l'avenir, il ne soit pas acceptable pour tout le monde de lire toutes les données, et surtout que cela puisse développer davantage de logique métier à l'avenir. Ces deux éléments sont plus probables si le projet réussit.

Tant que vous vous laissez un moyen de résoudre ces problèmes à l'avenir, quand et si vous en avez réellement besoin, je pense que votre conception fonctionnera. Je pense que vous devrez être très prudent pour séparer les problèmes dans le code JavaScript, et certains pourraient être réécrits sur le serveur plus tard.

Mais je pouvais certainement voir où cela pourrait valoir le risque de le faire plus tard par rapport à l'avantage de moins de pièces mobiles aujourd'hui.

0
psr

Si vous souhaitez construire SQL en JavaScript et l'envoyer à la base de données, qui vérifie les droits, etc., que pour des raisons de sécurité, ce serait un désastre. Tout simplement parce que lorsque vous construisez une API et construisez vous-même, vous ne devez analyser du point de vue de la sécurité que le nombre limité de requêtes. Si les requêtes sont générées en dehors de votre système, vous disposez d'un nombre potentiellement illimité de trucs que quelqu'un pourrait faire.

Mais ce n'est pas le cas puisque vous utilisez une base de données de valeurs-clés (pour autant que je sache, CouchDB tombe généralement dans cette catégorie). L'interface de base de données elle-même est une sorte de couche intermédiaire, et elle est testée pour des raisons de sécurité par l'équipe Apache. En raison de l'API JavaScript relativement simple, il est encore plus facile d'analyser les défauts potentiels que les interfaces complexes des applications JSF.

Cela peut être une solution sécurisée si vous effectuez des tests de sécurité complexes. Cela peut être encore plus facile que lors de l'utilisation de frameworks tels que JSF, qui utilisent souvent une API difficilement lisible. La sécurité par obscurité n'est pas considérée comme une solution.

Concernant votre question, ce ne sera pas un accès direct à la base de données de toute façon. L'accès direct serait la construction de requêtes SQL en JavaScript (malheureusement, j'ai vu de telles solutions). Dans votre cas, le CouchDB lui-même fournit la couche d'isolement. Vous pouvez bien sûr l'envelopper dans votre API pour le durcir, mais tant que vous pouvez facilement tester ce que peut faire un utilisateur particulier et si les contraintes de sécurité fonctionnent pour vous, vous aurez une solution sécurisée et robuste sans couches supplémentaires.

0
Danubian Sailor

Tout d'abord merci pour la question OUT OF THE BOX .... :)

Mais ce que je suggère, c'est; Essayez toujours de maintenir une ségrégation entre vos 3 couches. qui sont Présentation/Entreprise et Base de données ou DAO car ce sera la meilleure pratique dans ces types d'exigences et de configurations où il y aura beaucoup de changements chaque jour.

Dans les mondes simples, votre couche Présentation ne devrait pas connaître la couche Base de données, c'est-à-dire que le format de certains champs de type de date peut être différent de la couche Présentation et de la couche Base de données afin que l'utilisateur puisse avoir la liberté de sélectionner le format approprié de la date selon ses besoins.

Et Business Logic doit agir comme un couplage entre la couche de présentation et la couche base de données/Dao comme la conversion des champs, certaines validations commerciales, etc. doivent être traitées sur Business Layer plutôt que dans la section Javascript selon votre question.

Cette ségrégation vous offrira une grande facilité et un bon comportement lors de scénarios complexes, de fonctionnalités et même de validations complexes. Le meilleur avantage est: vous pouvez avoir différentes technologies pour implémenter ces couches et peut être modifié selon les besoins ou la portée de l'entreprise.

Merci

0
Logicalj

Je vois deux problèmes:

1. Couplage serré: Changer votre option DB? Eh bien, maintenant tu dois aussi changer tout ton code côté client. Croyez-moi. Nous n'avons pas besoin de plus de problèmes côté client.

2. Problème de sécurité TMI: Révèle beaucoup trop sur la façon dont les choses fonctionnent. L'authentification peut encore être un obstacle, mais trouver un exploit est beaucoup plus facile lorsque vous savez exactement ce qui se passe côté serveur.

Un niveau intermédiaire très très mince pourrait être une meilleure façon de procéder.

0
Erik Reppen