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?
Respuestas:
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).
fuente
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.
fuente
Reafirmando la pregunta
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
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:
En este sistema:
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:
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.
fuente
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:
fuente
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 :-)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
fuente