¿Por qué almacenar las contraseñas de los usuarios?


10

Ocasionalmente veo preguntas sobre cómo almacenar de forma segura las contraseñas de los usuarios para una aplicación web (usando un RDBMS, no estoy hablando de Facebook o Twitter). La respuesta habitual es "sal la contraseña, luego hash con un algoritmo fuerte como TDES o SHA512".

Mi pregunta es: como usuario de RDBMS, ¿por qué debería molestarme en absoluto porque la contraseña almacena problemas ya que la mayoría de los motores tienen un mecanismo de autenticación incorporado?

Por ejemplo, si algún usuario X desea crear una contraseña de usuario de cuenta Y en mi aplicación web, ¿cómo está emitiendo mal la siguiente consulta?

CREATE USER X WITH ENCRYPTED PASSWORD Y IN GROUP baseuser;

Luego, dentro de mi aplicación, el usuario puede abrir una conexión a la base de datos usando sus credenciales y no tengo que preocuparme por la administración de contraseñas.

Veo múltiples ventajas para este método:

  • Si el RDBMS decide que el algoritmo de cifrado necesita ser cambiado, no necesito tocar nada, solo para aplicar las actualizaciones de seguridad;
  • Me resulta fácil gestionar las autorizaciones de los usuarios. Si un usuario es promovido a un rol de administrador, solo tengo que agregarlo al grupo correspondiente;
  • Las inyecciones de SQL ahora no tienen sentido, ya que administro los permisos para permitir exactamente lo que quiero permitir a cada usuario en la base de datos (por ejemplo, en un foro como SO, agregar nuevas publicaciones, responder a las publicaciones, comentar y editar / eliminar sus propias preguntas / respuestas / comentarios);
  • Se puede usar una cuenta de usuario "anónimo" para conexiones no autenticadas a mi aplicación;
  • Cada usuario es el propietario de los datos que proporcionó.

Pero en prácticamente todas las preguntas que veo sobre este tema, parece haber un consenso general de que esta no es la forma en que se deben hacer las cosas. Mi pregunta es: ¿por qué?

Nota: El tercer punto está permitido por las políticas en PostgreSQL y las políticas de seguridad en Microsoft SQL Server. Me doy cuenta de que estos conceptos son nuevos, pero de todos modos, ahora que están aquí, ¿por qué la técnica que describo no se convierte en la forma estándar de manejar las cuentas de los usuarios?


2
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Paul White 9

Por cierto, la respuesta habitual es incorrecta. Debería ponerle sal a la contraseña, luego usar un algoritmo lento como bcrypt o argon2.
Tgr

Respuestas:


27

Porque para muchas aplicaciones, no quieren cuentas de usuario individuales conectadas a la base de datos. Los usuarios / contraseñas / derechos / permisos se manejan todos en la capa de aplicación, y se utiliza una única cuenta de servicio dedicada para conectarse al back-end de la base de datos.

Como DBA, no quiero tener que administrar, a nivel de la base de datos, los 10,000 usuarios activos de alguna aplicación web pública de tamaño medio, o tal vez los más de 2 millones de usuarios de alguna aplicación repentinamente popular.

En un sentido muy real, esta es una diferencia de filosofía entre los desarrolladores de aplicaciones y los desarrolladores de bases de datos / DBA.

Muchos / la mayoría de los desarrolladores de aplicaciones no van a querer pasar la responsabilidad de los aspectos principales de la funcionalidad de la aplicación y / o las reglas comerciales a la capa de base de datos. En cambio, ven la base de datos como una herramienta para simplemente almacenar y recuperar datos.

En algunos casos, esto puede ser miope; muchos RDBMS tienen características increíbles que podrían hacer que la vida de los desarrolladores de aplicaciones sea mucho más fácil (seguridad de nivel de fila, índices en columnas, almacenamiento de archivos, etc.).

Pero algunas de estas características más frescas solo están disponibles en versiones más nuevas, y las organizaciones no siempre se apresuran a actualizar los entornos existentes (consulte este gráfico de 2014 ).

Y en otros casos, se prefiere manejar esas cosas en la capa de aplicación (y no solo para la portabilidad de la plataforma de la base de datos, francamente creo que esa afirmación es exagerada).


2
Existe una 'guerra santa' en cuanto a si la lógica de negocios va en la aplicación o en la base de datos. Si ha creado una aplicación donde toda la lógica de negocios (en particular, la seguridad) está en la base de datos (utilizando procedimientos almacenados, vistas, etc.), entonces puede haber un argumento para utilizar mecanismos de seguridad de la base de datos porque nadie puede conectarse directamente y sortear seguridad. Estoy completamente de acuerdo en que debe evitar 'reconstruir' un mecanismo de seguridad (es decir, inicio de sesión / contraseña) en una tabla personalizada. ¿Por qué hacer eso cuando ya tiene seguridad de directorio activo / O365?
Nick.McDermaid

1
@ Nick.McDermaid Me gusta asegurarme de mezclar la lógica de negocios entre la base de datos y la aplicación de manera justa para ayudar a eliminar la posibilidad de que los futuros desarrolladores tengan alguna idea de lo que está sucediendo, también me ayuda a mantener la seguridad de mi trabajo ya que nadie está loco suficiente para querer manejarlo.
Der Kommissar

Agregue un servicio web y un servidor de aplicaciones tomcat allí y podría trabajar para IBM
Nick.McDermaid

8

La línea divisoria se está volviendo un poco esponjosa en ese punto, pero consideraría que los usuarios y los permisos en el nivel de la base de datos son parte del esquema y no parte de los datos, y en general las aplicaciones no tienen lugar para modificar el esquema (hay, como siempre, excepciones a esta regla).

Prefiero no dar a las aplicaciones los permisos que necesitan para administrar objetos de esquema (inicios de sesión, usuarios y permisos) ya que se necesitan nuevos usuarios y los antiguos se van, porque si esa aplicación es pirateada, el atacante tiene acceso a esos permisos haciendo que sea más fácil descifrar la base de datos aún más. En MS SQL Server, a menos que esté utilizando bases de datos totalmente contenidas, los inicios de sesión son objetos a nivel de servidor, por lo que debe entregar derechos más allá de la base de datos de una sola aplicación, lo que lo hace aún más riesgoso.

Además, incluso si tiene cuentas de usuario por aplicación en su nivel de base de datos, todavía necesita cuentas de usuario de nivel de aplicación para atender solicitudes no autenticadas, es decir, si la aplicación necesita información de la base de datos antes de que el usuario de la aplicación se haya autenticado con éxito (quizás para mostrar información de estado en la pantalla de bienvenida / inicio de sesión?).

Además, si el objetivo es la portabilidad entre los motores de la base de datos (¿tal vez su aplicación quiere poder ejecutarse tanto en mysql como en postgres?), Entonces sus aplicaciones necesitarán resumir las funciones de administración de usuario / inicio de sesión para cada motor, ya que no son estándar entre ellos - Si va a hacer ese esfuerzo, también podría implementar contraseñas usted mismo y obtener las opciones de administración que desee en lugar de aceptar el conjunto de características comunes más bajo que ofrecen los motores.


1
Ok, entonces la "aplicación no debería alterar el esquema" es, en mi opinión, el primer buen punto contra la técnica que sugiero. Sin embargo, la cuenta anónima capaz de crear nuevos usuarios solo necesita poder crear nuevos usuarios con el acceso más básico. Solo los administradores pueden promover a los usuarios y eliminarlos, lo que supongo que es lo que se desea en las aplicaciones :-) Los datos generales son visibles para el usuario anónimo, por lo que esta conexión se puede usar para contenido donde no se necesita autenticación. La portabilidad también es un buen punto, pero creo que los comandos de usuario ahora son parte del estándar (no estoy seguro, no era hace años)
Fabian Pijcke

Por cierto, con esta configuración, si un hacker obtiene acceso a la base de datos como usuario anónimo, podrá crear tantos usuarios como desee, pero esto no es un problema de seguridad, seguramente también podría inflar la base de datos usando uno de las cuentas creadas, eso sería molesto pero de nuevo no sería un problema de seguridad (y de todos modos podría hacerlo utilizando la interfaz estándar, sería mucho más lento: p)
Fabian Pijcke

3
Estoy de acuerdo en que, desde el punto de vista de la seguridad, los usuarios de la base de datos serían mejores. Sin embargo, eso es básicamente imposible de gestionar, por ejemplo, en tiendas en línea donde puede tener 50 millones de usuarios registrados. Cada uno necesitaría ser un usuario de la base de datos. Además: esto generalmente no funciona bien con aplicaciones web que usan un grupo de conexiones.
a_horse_with_no_name

6

Reafirmando la pregunta

¿Por qué almacenar las contraseñas de los usuarios?

La respuesta más simple es que tienes que hacerlo. Todavía almacena contraseñas en su método alternativo. Es solo que utiliza el sistema integrado de la base de datos para administrar el almacenamiento. Por lo tanto, su método es tan bueno como el de su base de datos. Eso puede ser mejor que lo que sea que hagas de otra manera, pero no es evitar el almacenamiento. Realmente es solo evitar el almacenamiento de codificación.

También podría no ser mejor. Si comprometo una base de datos y obtengo copias de los archivos, puedo acceder a las tablas directamente. Por lo tanto, no tiene sentido utilizar un brillante sistema de administración de contraseñas. Porque si alguien puede acceder a la tabla de nivel del sistema que contiene las contraseñas o las contraseñas hash, también puede acceder a los archivos directamente. ¿Por qué molestarse con descifrar contraseñas cuando ya tiene los datos? No es como si pudiera cifrar los datos fácilmente tampoco. Cada usuario debe poder acceder a él. Por lo tanto, el cifrado a nivel de usuario no funcionará tan bien.

Pero lo que realmente parece estar preguntando es

¿Por qué usar un esquema de autenticación de nivel de aplicación cuando la base de datos ya tiene uno?

Seguridad

Ignorando la posibilidad de que pueda escribir una versión más segura, otros han sugerido una serie de razones. En general estoy de acuerdo. Pero hay otro que nadie ha mencionado todavía. Está comprometiendo la seguridad de su base de datos.

En este sistema, cada usuario de su aplicación tiene un usuario y una contraseña de la base de datos. Claro, es un usuario limitado, pero sigue siendo un usuario que puede conectarse a la base de datos. Incluso si usa seguridad de nivel de fila, todavía permite que los usuarios finales conozcan la información de conexión de la base de datos. Si alguna vez hay un exploit en el que un usuario puede obtener un acceso a nivel de tabla, ha abierto su base de datos para atacar. Y algunos exploits han ido más allá de eso al acceso del administrador.

En las capas de la cebolla de seguridad, el sistema normal es:

  • Base de datos, que solo permite conexiones desde ciertas máquinas.
  • Base de datos, solo permite conexiones como ciertas combinaciones de usuario / contraseña.
  • Servidores con permisos de base de datos que permiten conexiones desde aplicaciones.
  • Las aplicaciones se ejecutan en el servidor.
  • Las aplicaciones tienen información de conexión de base de datos con privilegios limitados.
  • Las aplicaciones autentican a los usuarios antes de permitirles modificar la base de datos (excepto posiblemente para crear nuevas cuentas).

En este sistema:

  • Los usuarios finales conocen combinaciones de usuario / contraseña que funcionarán en la base de datos, ciertamente con privilegios muy bajos.
  • Solo necesita comprender un servidor o simular de manera convincente que es un servidor autorizado.

Hemos perdido todo el nivel de seguridad de la aplicación. Y hemos renunciado voluntariamente a parte de la capa de la base de datos. Entonces solo necesitamos dos exploits:

  1. Falsificar o comprometer un servidor autorizado.
  2. Aumente el acceso de la cuenta con privilegios limitados.

Si podemos hacer esas dos cosas, tenemos acceso a la base de datos. Entonces pasamos de tres capas a dos. (La tercera capa en el sistema normal es que necesita un usuario válido para conectarse a la base de datos).

Vas a estar administrando muchas de estas cuentas. ¿Qué pasa si cometes un error? En lugar de limitar al usuario X a solo ciertas filas, les da a todos acceso a una tabla crítica. Ese tipo de cosas normalmente se realiza manualmente y solo hay unas pocas, por lo que son fáciles de auditar. Pero en su sistema, podría estar haciendo miles o millones o incluso miles de millones de cuentas de usuario, cada una con su propio acceso idiosincrásico.

Para el caso, ¿el sistema de la base de datos se escala a millones o miles de millones de usuarios? Si es así, ¿qué pasa con el número de reglas? Si cada usuario toma un centenar o más de reglas sobre lo que puede y no puede acceder, ¿eso aumenta hasta mil millones de usuarios? Está tomando un sistema normalmente a pequeña escala y lo está haciendo a gran escala. Eso no necesariamente funcionará. Puede encontrar limitaciones del sistema a medida que crece.


5

Lo que describa manejará la autenticación, pero no la autorización (a qué datos puede acceder el usuario) o solo en el caso de uso más simple.

Para continuar con su ejemplo con stackexechange: ¿Cómo haría que la publicación eliminada solo sea visible para el usuario de alta representación? Entonces, para las reglas de acceso, aún necesitará lógica en el código. En lugar de compartir la lógica de acceso entre las reglas de la base de datos y las reglas de acceso aplicativo, la mayoría de los desarrolladores prefieren tenerlas todas en el mismo lugar.

También necesitará una tabla para almacenar la información del usuario: un usuario no es solo un nombre de usuario + contraseña. Tiene un correo electrónico, una reputación, etc. Por lo tanto, aún necesita la tabla de usuario, que debe asegurarse de que esté sincronizada con la tabla de usuario de la base de datos, siempre que pueda acceder a ella.

Con su solución, puede omitir una columna de contraseña, que no es tan difícil de completar: hay buenas bibliotecas y documentación sobre cómo manejar / contraseñas hash.

Otro punto: ¿cómo crearía un grupo de conexiones? Solo conozco jdbc (java <-> db), y debe proporcionar un nombre de usuario + contraseña para obtener una conexión, que luego puede agrupar.

Pensé en algunos otros puntos que serán más difíciles / complicados de implementar que con la forma establecida:

  • manejo de recuperación de contraseña
  • 2 años después de la implementación inicial, su gerente de producto le pide que agregue soporte para el esquema oauth, o permita la autenticación de doble factor

Algo así CREATE POLICY deleted_posts_high_rep ON posts FOR SELECT TO baseuser USING ((SELECT rep FROM users WHERE name = current_user()) > 10000)responde tu primera pregunta. Nunca dije que ya no necesitaba una tabla de usuarios, y garantizar la sincronización con la tabla de usuarios de db es algo complicado pero posible. El punto principal de la técnica discutida es la seguridad. En cuanto al grupo de conexiones, trabajo con OCaml y tengo que decir que no entiendo por qué necesitaría un grupo de conexiones. Actualmente utilizo un mapa hash que asocia valores de cookies a funciones 0-ary que devuelven conexiones :-)
Fabian Pijcke

55
El grupo de conexiones se implementa para mejorar el rendimiento: con ellos, no es necesario establecer una conexión para cada solicitud de usuario (por lo que guarda cpu / io / latencia al crear el enlace tcp + toda la conexión y el intercambio de autenticación con la base de datos). En cuanto a la definición de la política: su base de datos verificará constantemente el acceso en cada acceso a los datos, incluso cuando ya los haya verificado una vez. Además, 'acceso denegado o prohibido' no es lo mismo que 'OK, ningún resultado'. No estoy seguro de que los de seguridad prefieran la versión OK.
Thierry

3
Fabian, la agrupación de conexiones es fundamental en cualquier tipo de escala, es realmente un valor predeterminado que ni siquiera considerarías no usar. Aquí hay algunos puntos de referencia solo para darle una idea de lo importante que es: un aumento del rendimiento de 600x con la agrupación de conexiones ( vladmihalcea.com/2014/04/17/the-anatomy-of-connection-pooling ) y un aumento del rendimiento de más de 4.000x con agrupación de conexiones ( progress.com/tutorials/jdbc/… ). Es una diferencia de varios órdenes de magnitud, no es "agradable de tener", las aplicaciones se detendrían sin ella.
Ivan McA

1
Números interesantes Y, de hecho, nunca he visto una aplicación que no use grupos de conexiones. Pero no sabía (y esperaba) que hicieran tanta aceleración. El otro aspecto que obtiene con el grupo de conexión es el control de recursos: gracias a ellos, un gran aumento en el cliente que intenta conectarse de una sola vez hará que su aplicación sea lenta, pero su base de datos no se verá afectada tanto (si el grupo está bien configurado) .
Thierry

Ok, acabo de buscar más información sobre los grupos de conexiones, y estoy de acuerdo en que este es un punto muy válido tan pronto como el sitio web tiene que manejar más de cien conexiones por segundo, lo que no es tan alto. ¡Parece que cada conexión en PostgreSQL consume alrededor de 10MiB de RAM! Nunca pensé que fuera tanto.
Fabian Pijcke

1

Otro punto: muchas [1] aplicaciones web le permiten registrarse y crear una cuenta de usuario en línea a través de la aplicación misma. ¡Lo que significa que su usuario anónimo (que debería tener los menos privilegios que uno asumiría) tiene que tener derechos para crear usuarios y otorgar privilegios!

De acuerdo, es posible limitar los privilegios que podría otorgar, y ofrecer a los usuarios de nivel superior más opciones de concesión (no sé si es así, no es "otorgar privilegios" un solo privilegio a menudo). Pero aún así, significa poner algo en línea con privilegios de subvención para que todos puedan piratear. Estoy bastante seguro de que mi DBA no me gustaría si lo hiciera :)

Sé que, en cierto nivel, este problema existe de todos modos, pero tiene capas de defensa, especialmente para eliminar datos, si no permite que la aplicación web administre usuarios de DB.

Además, esto evitaría el uso de conexiones de bases de datos agrupadas o reutilizadas.

[1] La mayoría diría, pero no cifras que lo respalden

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.