¿Hay alguna razón para no pasar directamente de Javascript del lado del cliente a una base de datos?

60

Entonces, digamos que voy a construir un clon de Stack Exchange y decido usar algo como CouchDB como mi tienda backend. Si uso su autenticación integrada y la autorización a nivel de base de datos, ¿hay alguna razón para no permitir que el Javascript del lado del cliente escriba directamente en el servidor CouchDB disponible públicamente? Dado que se trata básicamente de una aplicación CRUD y la lógica de negocios consiste en "Solo el autor puede editar su publicación" No veo la necesidad de tener una capa entre el contenido del lado del cliente y la base de datos. Simplemente usaría la validación en el lado de CouchDB para asegurarme de que alguien no está colocando datos de basura y asegurándome de que los permisos se configuren correctamente para que los usuarios solo puedan leer sus propios datos de _usuario. El renderizado se haría del lado del cliente por algo como AngularJS. En esencia, puedes tener un servidor CouchDB y un montón de páginas "estáticas" y estarás listo. No necesitaría ningún tipo de procesamiento del lado del servidor, solo algo que pueda servir las páginas HTML.

La apertura de mi base de datos al mundo parece incorrecta, pero en este escenario no puedo pensar por qué mientras los permisos se configuren correctamente. Va en contra de mi instinto como desarrollador web, pero no puedo pensar en una buena razón. Entonces, ¿por qué es una mala idea?

EDIT: Parece que hay una discusión similar aquí: Escribiendo Web "server less" aplicaciones

EDITAR: ¡Fantástica discusión hasta ahora, y aprecio los comentarios de todos! Siento que debería agregar algunas suposiciones genéricas en lugar de mencionar a CouchDB y AngularJS específicamente. Así que asumamos que:

  • La base de datos puede autenticar usuarios directamente desde su tienda oculta
  • Todas las comunicaciones de la base de datos se realizarán a través de SSL
  • La validación de datos puede (pero ¿quizás no debería?) ser manejada por la base de datos
  • La única autorización que nos importa más que las funciones de administración es que solo se le permita a alguien editar su propia publicación
  • Estamos perfectamente bien con que todos puedan leer todos los datos (EXCEPTO los registros de usuarios que pueden contener hashes de contraseña)
  • Las funciones administrativas estarían restringidas por la autorización de la base de datos
  • Nadie puede agregarse a un rol de administrador
  • La base de datos es relativamente fácil de escalar
  • Hay poca o ninguna lógica empresarial verdadera; esta es una aplicación básica de CRUD
pregunta Chris Smith 19.12.2012 - 15:34
fuente

15 respuestas

47

Hacer lo que usted sugiere crea un acoplamiento estrecho entre su idioma del lado del cliente y su base de datos.

Puede estar bien, hay menos código para escribir y mantener, y en teoría, la depuración podría / debería ir un poco más rápido.

Por otro lado, hace que otros aspectos sean más difíciles. Si / cuando necesite cambiar cualquiera de esas tecnologías, tendrá más dificultades debido al estrecho acoplamiento entre ellas.

Protegerse contra los ataques será (bastante) un poco más difícil. Está asumiendo que el cliente siempre presentará solicitudes bien formateadas a la base de datos. Eso supone que nadie hackeará el código del lado del cliente para insertar declaraciones maliciosas. En otras palabras, "tomarán prestados" sus mecanismos de autenticación y reemplazarán el código de cliente normal con el de ellos.

No lo recomendaría, y muchos te dirían vehementemente que no lo hagas. Pero se puede hacer.

    
respondido por el GlenH7 19.12.2012 - 15:54
fuente
36

Probablemente no sea una gran idea. Y la primera y más poderosa razón por la que puedo dar es que un servidor de base de datos no está diseñado para ser un servidor web público. Al contrario, la sabiduría convencional dice que debes ocultar tu base de datos detrás de un cortafuegos.

Si necesita evidencia de apoyo, hay muchas preocupaciones, no todas insuperables, pero hay muchas cosas en las que pensar. En ningún orden en particular, aquí hay algunos:

  • No puede realizar el saneamiento de consultas, porque le está enviando las consultas directamente.
  • Los permisos de la base de datos tienden a funcionar de manera diferente a los permisos de la aplicación y del servidor web. Los servidores web y los marcos de aplicaciones lo inician sin nada, y necesita crear y exponer explícitamente recursos individuales, puntos finales y acciones. Las bases de datos, por otro lado, le piden que otorgue roles a un alto nivel.
  • Probablemente no esté bien optimizado para sostener la carga de trabajo de un servidor web; no puede beneficiarse de la agrupación de conexiones.
  • Los servidores web más populares se han dividido en mucho . Y han recibido muchos parches de seguridad. Básicamente, su DBMS ha sido diseñado para ocultarse detrás de un firewall, por lo que probablemente no haya sido probado ni por una fracción del porcentaje de las amenazas potenciales que enfrentará en la web pública.
  • Usted debe usar el lenguaje de consulta de la base de datos para proteger los datos privados. Dependiendo de su DBMS, eso puede ser desafiante.
  • Usted debe usar el lenguaje de consulta de la base de datos para filtrar grandes conjuntos de datos, algo que podría intentar hacer de todos modos; pero algo que puede convertirse en una carga para reglas comerciales más complicadas.
  • Soporte limitado o nulo para bibliotecas de terceros.
  • Soporte comunitario muy limitado (potencialmente cero) para muchos de los problemas que encontrará.

... Y estoy seguro de que hay otras preocupaciones. Y estoy seguro de que hay una solución para la mayoría, si no todas estas preocupaciones. ¡Pero hay una lista para que comiences!

    
respondido por el svidgen 19.02.2016 - 23:20
fuente
16

La mejor y única razón que puedo imaginar es: porque este método no es apoyado o recomendado directamente por ninguna de las partes involucradas.

Los proveedores de navegadores, los estándares de EcmaScript, los desarrolladores de sistemas de bases de datos, las compañías de equipos de redes, los arquitectos de alojamiento / infraestructura y los especialistas en seguridad no respaldan activamente (o tal vez consideren) su caso de uso propuesto. Este es un problema, porque su método propuesto requiere que todas estas entidades, y más, funcionen adecuadamente para su aplicación, aunque ninguno de los sistemas involucrados fue diseñado para respaldar esto.

No estoy diciendo que no sea posible. Solo digo que esto es menos como "reinventar la rueda" y más como reinventar la interacción cliente-servidor basada en el navegador.

En el mejor de los casos, harás un montón de trabajo para que los sistemas funcionen al nivel más básico posible. Las bases de datos populares y modernas no tienen REST o están diseñadas para funcionar a través de HTTP, por lo que estará creando sus propios controladores de cliente basados en WebSocket (supongo).

Incluso si logra que todo funcione técnicamente, renunciará a muchas de las características más poderosas de las arquitecturas modernas. No tendrá una defensa en profundidad; todos pueden conectarse fácilmente directamente al objetivo principal de la mayoría de los intentos de piratería de sitios web. Pero el escenario que propones es mucho, mucho peor que eso.

El modelo propuesto no solo está exponiendo el servidor, sino que está exponiendo cadenas de conexión válidas. Los atacantes no pueden simplemente hacer ping al servidor: pueden iniciar sesión activamente y alimentarlo con comandos. Incluso si puede limitar el acceso a los datos, no estoy al tanto de las herramientas suficientes en los sistemas DBMS para protegerse de los escenarios de denegación de servicio y su tipo. Cuando se trabaja en versiones mejoradas de SQL, como TSQL, a menudo es trivialmente fácil producir bombas que funcionan de manera infinita (unas pocas combinaciones sin restricciones para producir un producto cartesiano y tendrá un SELECTO que funcionará para siempre, haciendo un trabajo pesado) . Me imagino que necesitaría deshabilitar la mayoría de las funciones de SQL, incluso eliminando las consultas básicas de SELECT con JOIN y quizás solo permitir llamadas a procedimientos almacenados. Ni siquiera sé si puedes hacer eso, nunca me han pedido que lo intente. No suena bien.

La escalabilidad de la base de datos también suele ser uno de los problemas más difíciles al trabajar a gran escala, mientras que la ampliación de varios servidores HTTP, especialmente con páginas estáticas o en caché, es una de las partes más fáciles. Su propuesta hace que la base de datos realice más trabajo al ser responsable básicamente del 100% de la actividad del lado del servidor. Esa es una falla asesina por sí misma. Lo que gana al trasladar el trabajo al cliente que pierde al mover más trabajo a la base de datos.

Finalmente, solo me gustaría señalar que el corazón de lo que proponen no es nuevo, sino que se remonta a décadas. Este modelo se denomina modelo de "base de datos completa", que básicamente movió la mayoría de la lógica del lado del servidor a la base de datos tal como lo propuso. Hay muchas razones por las que este modelo se ha ido por el camino en la Internet masiva, y probablemente sería informativo mirar más en esa historia. Tenga en cuenta también que incluso entonces no se tuvo en cuenta el hecho de que los usuarios que no son de confianza puedan iniciar sesión en el sistema y ejecutar comandos, ya que el acceso aún se controlaría para seleccionar usuarios internos (conocidos) que no debían atacar el sistema constantemente. / p>

El hecho es que todavía necesitará un servidor HTTP para servir archivos, ya que los sistemas de bases de datos simplemente no lo hacen. Al mismo tiempo, todo lo que usted propone puede obtenerse utilizando un modelo de servidor ligero (como con Nodejs) para exponer una interfaz RESTful a su base de datos. Esto es popular por una razón: funciona, mantiene la base de datos oculta detrás de las capas de protección, es extremadamente escalable y, sin embargo, le permite crear su base de datos tan gruesa o tan delgada como quiera.

    
respondido por el BrianH 20.02.2016 - 00:14
fuente
8
  

Dado que esto es básicamente una aplicación CRUD y la lógica de negocios consiste en "Solo el autor puede editar su publicación" No veo la necesidad de tener una capa entre las cosas del lado del cliente y la base de datos. Simplemente usaría la validación en el lado de CouchDB para asegurarme de que alguien no está colocando datos de basura y asegurándome de que los permisos se configuren correctamente para que los usuarios solo puedan leer sus propios datos de usuario.

Bueno, colocar su autorización (las preocupaciones de seguridad) y la validación lógica fuera de la Base de datos proporciona una separación de las preocupaciones en su sistema de software. Por lo tanto, puede probar, mantener, escalar y reutilizar sus bloques de códigos lógicos con menos riesgos de frenar la funcionalidad en el sistema.

Proporcionar capacidad para que los clientes puedan comunicarse directamente con la base de datos tiene un gran potencial para arruinar los datos .

Esto también significa que evitar / eliminar acoplamiento apretado hace que su sistema de software sea más fácil de mantener y SOLID.

    
respondido por el EL Yusubov 19.12.2012 - 15:54
fuente
6

Dejar que el usuario interactúe con la base de datos directamente me parece realmente peligroso.

¿Es el mecanismo de autenticación de CouchDB realmente tan sofisticado que puede aislar el acceso de lectura y escritura de un usuario solo a los datos que se supone que debe leer y escribir (estamos hablando de por documento, quizás incluso por documento)? - privilegios de acceso al campo aquí)? ¿Qué pasa con los datos "comunitarios" que comparten varios usuarios? ¿No existe esto en absoluto en el diseño de su aplicación?

¿Realmente desea que el usuario pueda cambiar sus datos de CUALQUIER modo? ¿Qué pasa con las inyecciones de XSS, por ejemplo? ¿No sería mejor tener una capa de servidor para filtrarlas antes de que ingresen a la base de datos?

    
respondido por el Philipp 19.12.2012 - 17:39
fuente
6

Ha obtenido varios motivos, pero aquí hay uno más: la prueba de futuro. Tarde o temprano, a medida que su aplicación evolucione, se le presentarán algunos requisitos que no se pueden cumplir de forma fácil o segura en JS del lado del cliente o como un procedimiento almacenado en su base de datos.

Por ejemplo, le dicen que todos los nuevos registros deben tener una verificación de CAPTCHA para ser válidos. Esto sería bastante fácil con casi cualquier marco de aplicación web moderno. Simplemente coloque una reCAPTCHA en el formulario de registro, pase el token de respuesta de reCAPTCHA al backend y agregue un par de líneas de código a su backend para verificar la validez del token con la API de Google (o mejor aún, use una biblioteca que alguien más escribió para que lo haga por usted).

Si está utilizando un sistema de dos niveles y confía en la base de datos para toda la lógica del lado del servidor, ¿cómo va a verificar el token? Sí, supongo que podría ser teóricamente posible, dependiendo del DBMS, escribir un procedimiento almacenado que de alguna manera llame a un shell e invoque curl con los argumentos adecuados. También es casi una idea horrible: el filtrado de entradas y la protección contra vulnerabilidades de seguridad sería terrible; Tendrías problemas con el manejo de errores y los tiempos de espera; y tendrías que analizar la respuesta tú mismo. Sin mencionar que un DBMS no tiene la intención de hacer esto, por lo que no hay razón para pensar que el rendimiento, la estabilidad, la seguridad de subprocesos, etc. no sean problemas. Ver, por ejemplo, este hilo , que analiza algunos de estos problemas para Postgres.

Y eso es solo el problema de agregar un CAPTCHA simple a un formulario. ¿Qué va a hacer si desea agregar la verificación por SMS o un trabajo en segundo plano que envíe correos electrónicos a los usuarios inactivos para recordarles su aplicación o agregar una función de carga de archivos para que las personas puedan establecer una imagen de perfil? Tal vez usted decide que su aplicación debería tener algunas pruebas automatizadas algún día? ¿O que le gustaría hacer un seguimiento de los cambios en sus procedimientos en un sistema de control de versiones? Existen numerosas bibliotecas y herramientas para que la mayoría de los lenguajes útiles manejen la mayoría de estas tareas por usted, pero pocas o ninguna estarán disponibles para su DBMS, porque no está destinado a hacerlo.

Eventualmente, querrás hacer algo que razonablemente no puedes hacer directamente en tu DBMS, y luego estarás atascado. Debido a que habrá construido toda la aplicación en su DBMS, no tendrá otra alternativa que no sea obtener un servidor web y comenzar a reconstruir piezas en otro idioma, solo para agregar una característica simple.

Y eso sería una verdadera lástima, porque ya tenemos un nombre para el lugar donde colocó la lógica de su aplicación y se llama "código fuente de su aplicación" en lugar de "procedimientos almacenados de base de datos" por una razón.

    
respondido por el Zach Lipton 20.02.2016 - 05:11
fuente
5

Si sus controles de seguridad y lógica empresarial están contenidos en el javascript del lado del cliente, un usuario malintencionado puede anularlo. Como alternativa, puede aprovechar una tecnología del lado del servidor basada en JavaScript (como Node.JS ) para manejar la validación, autorización y similares.

    
respondido por el Michael Brown 19.12.2012 - 16:24
fuente
2

Cualquier restricción comercial que desee garantizar debe ser validada por el lado del servidor. Incluso si controla el acceso de los usuarios, alguien puede enviar datos no válidos.

Siguiendo el ejemplo de clonación de stackoverflow:

  • ¿Cómo bloquearía las preguntas "cerradas" en el sitio para que no se editen de todos modos?
  • ¿Cómo evitaría que las personas eliminen comentarios?
  • ¿Cómo evitarías que las personas falsificaran las fechas de los comentarios?
  • ¿Cómo evitarías que las personas voten 50 veces más por la misma publicación?
  • Probablemente hay muchos más ejemplos si cavas un poco más.

Cualquiera podría manipular el código del lado del cliente y violar completamente la integridad de los datos (incluso si está restringido a ciertos objetos, como sus propias publicaciones).

    
respondido por el Jbm 20.12.2012 - 06:33
fuente
1

Edite la página en firebug y en algún punto ponga una línea similar a esta:

ExecDbCommand("DROP TABLE Users")

Ejecutalo.

Editar:

La pregunta era, de hecho, sobre CounchDB, por lo que no hay sql para ejecutar aquí. Sin embargo, la idea es la misma. Supongo que cualquier aplicación no trivial depende de los datos para respetar algunas reglas de consistencia que son verificadas / aplicadas por el código de la aplicación. Un usuario malintencionado puede modificar el código del cliente para guardar datos en un formulario que infrinja las reglas de su negocio y podría causar estragos en su aplicación.

Si su sitio considera que todos los estados de datos posibles son válidos desde una perspectiva comercial, entonces, por todos los medios, siga esta ruta, pero si este no es el caso (es probable), querrá tener la garantía de que cualquier dato que se almacene es generado por su código y de acuerdo con sus reglas .

    
respondido por el AZ01 19.12.2012 - 17:39
fuente
1

Vieja pregunta, lo sé, pero quería intervenir porque mi experiencia es muy diferente a las otras respuestas.

He pasado muchos años escribiendo aplicaciones colaborativas en tiempo real. El enfoque general para estas aplicaciones es replicar los datos localmente y sincronizar los cambios con los compañeros lo más rápido posible. Todas las operaciones en datos son locales, por lo que todo el almacenamiento de datos, el acceso a datos, la lógica de negocios y la interfaz de usuario son capas son locales. El movimiento "sin conexión primero" ( enlace ) ha adoptado este enfoque para crear aplicaciones web sin conexión y puede tener algunos recursos relevantes. Este tipo de casos de uso no solo obligan a abrir la capa de acceso a los datos a los clientes, sino también al almacenamiento de datos. Sé que sé. Parece una locura, ¿verdad?

Las preocupaciones por tales aplicaciones sin conexión en primer lugar son similares a lo que has pedido, solo un nivel eliminado. Me parece relevante. Dado que está abriendo el acceso directo de datos a los clientes, la pregunta es: ¿cómo puede limitar los efectos de un usuario malintencionado? Bueno, hay muchas estrategias, pero no son obvias si proviene de un fondo de desarrollo más tradicional.

El primer error es que exponer la base de datos significa exponer todos los datos. Tome CouchDB por ejemplo; Las bases de datos en CouchDB son livianas, por lo que no debería pensar en crear cientos de miles de bases de datos separadas en un servidor. Los usuarios solo pueden acceder a las bases de datos a las que se les otorga permiso para acceder como lectores o escritores (por no hablar de las características de validación y de lo que no es CouchDB), por lo que solo pueden acceder a un subconjunto de datos.

¡La segunda idea errónea es que un usuario cagando datos es un problema! Si a los usuarios se les da una réplica de una base de datos, pueden cagarla en todo lo que quieran sin afectar a otros usuarios. Sin embargo, debe validar sus cambios antes de replicar sus datos en el almacén "central". Piense en Git: los usuarios pueden hacer lo que quieran en sucursales, bifurcaciones y repositorios locales sin afectar la rama principal. La fusión con el maestro implica mucha ceremonia y no se hace a ciegas.

Estoy creando un sistema actualmente utilizando CouchDB donde los usuarios necesitan colaborar en los datos para crear un conjunto de datos que luego se "publica" a través de un flujo de trabajo de control de calidad / control de calidad. La colaboración se lleva a cabo en una réplica de los datos (a esto le llamamos una base de datos de prueba o de trabajo), y una vez completada, una persona responsable realiza QA / QC en los datos y solo después se replica en el repositorio principal.

De esto se derivan muchos beneficios que son difíciles de lograr en otros sistemas, como el control de versiones, la replicación y la colaboración (¡a lo largo de trabajar sin conexión!) para las aplicaciones tradicionales de CRUD de tres niveles es muy difícil.

Mi consejo: si tu aplicación es "tradicional", hazlo de la manera tradicional. Si alguna de las cosas que mencioné anteriormente (aunque hay muchas más ...) se aplican a ti, entonces considera las arquitecturas alternativas y prepárate para pensar lateralmente.

    
respondido por el Daniel Paull 30.08.2018 - 04:40
fuente
0

Creo que, dadas todas sus suposiciones, es posible pasar directamente del cliente a la base de datos. Sin embargo, es razonable considerar si sus suposiciones son válidas y es probable que sigan siéndolo en el futuro.

Me preocuparía que en el futuro no esté bien que todos lean todos los datos y, especialmente, que pueda desarrollar más lógica empresarial en el futuro. Ambos son más probables si el proyecto tiene éxito.

Siempre y cuando te dejes una forma de enfrentar estos problemas en el futuro, cuando necesites resolverlos, creo que tu diseño funcionará. Creo que tendrá que tener mucho cuidado para separar las preocupaciones en el código de JavaScript, y algunas de ellas podrían volver a escribirse en el servidor más adelante.

Pero definitivamente podría ver dónde podría valer la pena el riesgo de hacerlo más tarde en lugar del beneficio de tener menos partes móviles hoy.

    
respondido por el psr 19.12.2012 - 19:14
fuente
0

En primer lugar, gracias por la pregunta FUERA DE LA CAJA .... :)

Pero lo que sugeriría es; Siempre trata de mantener una segregación entre tus 3 capas. que son Presentation / Business y Database o DAO porque esa será la mejor práctica en ese tipo de requisitos y configuraciones donde habrá muchos cambios todos los días.

En los mundos simples, su capa de presentación no debe conocer la capa de la base de datos, es decir, el formato de algunos campos de tipo de fecha puede ser diferente de la capa de presentación y la capa de la base de datos para que el usuario pueda elegir libremente el formato de la fecha según su necesidades.

Y la lógica de negocios debe actuar como un acoplamiento entre la capa de presentación y la base de datos / capa de Dao, como la conversión de campos, algunas validaciones de negocios, etc. deben manejarse en la capa de negocios en lugar de en la sección de Javascript según su pregunta.

Esta segregación le proporcionará una gran facilidad y comportamiento durante escenarios complejos, funcionalidades e incluso validaciones complejas. La mejor ventaja es: puede tener diferentes tecnologías para implementar estas capas y se puede cambiar según las necesidades o el alcance del negocio.

Gracias

    
respondido por el Logicalj 20.12.2012 - 06:16
fuente
0

Si desea compilar SQL en JavaScript y enviarlo a la base de datos, que verifica los derechos, etc., por razones de seguridad, sería un desastre. Simplemente porque cuando construye una API y, si usted mismo realiza consultas, debe analizar desde el punto de vista de la seguridad solo el número limitado de consultas. Si las consultas se crean fuera de su sistema, tiene un número potencialmente ilimitado de trucos que alguien podría hacer.

Pero no es el caso, ya que está utilizando una base de datos de valor-clave (por muy justo que yo sepa, CouchDB generalmente se encuentra en esa categoría). La interfaz de la base de datos en sí misma es un tipo de capa intermedia, y el equipo de Apache lo prueba por razones de seguridad. Debido a la API de JavaScript relativamente simple, es incluso más fácil analizar posibles fallas que las interfaces tan complicadas que tienen las aplicaciones JSF.

Esta puede ser una solución segura si realiza pruebas de seguridad complejas. Esto puede ser incluso más fácil cuando se usan marcos como JSF, que a menudo usan una API difícil de leer. La seguridad por oscuridad no se considera una solución.

En relación con su pregunta, de todos modos no será un acceso directo a la base de datos. El acceso directo sería la construcción de consultas SQL en JavaScript (desafortunadamente, he visto tales soluciones). En su caso, el propio CouchDB proporciona la capa de aislamiento. Por supuesto, podría envolverlo en su API para fortalecerlo, pero siempre que pueda probar fácilmente lo que un usuario en particular puede hacer y si las restricciones de seguridad le funcionan, tendrá una solución segura y robusta sin capas adicionales.

    
respondido por el Danubian Sailor 19.12.2012 - 19:46
fuente
0

Veo dos problemas:

1. Tight Coupling: ¿Cambiar la opción de DB? Bueno, ahora también tienes que cambiar todo el código del lado del cliente. Créeme. No necesitamos más problemas en el lado del cliente.

2. Problema de seguridad de TMI: revela demasiado sobre cómo funcionan las cosas. La autenticación podría seguir siendo un obstáculo, pero encontrar un exploit es mucho más fácil cuando sabes exactamente lo que está sucediendo en el servidor.

Un nivel medio muy, muy delgado podría ser una mejor manera de avanzar.

    
respondido por el Erik Reppen 20.12.2012 - 08:49
fuente
-1

Su cliente no puede usar su aplicación web si JavaScript está deshabilitado (o no es compatible con el navegador de su dispositivo) si javascript es la única capa de acceso a la base de datos.

    
respondido por el k3b 19.12.2012 - 16:10
fuente

Lea otras preguntas en las etiquetas