¿Cómo maneja la seguridad de la base de datos desde una aplicación de escritorio?

12

Durante unos 10 años, he trabajado en varias aplicaciones internas de clientes de escritorio con almacenes de datos de SQL Server. Raramente comencé estos proyectos, la mayoría son trabajos de adquisición.

Una cosa que parecía constante en todas partes era que había una sola cuenta de usuario global de SQL Server que esta aplicación usaba que le otorgaba permiso para la base de datos común, y sí, en algunas situaciones ingenuas usaba la sacuenta de usuario, que generalmente intentaba arreglar cuando era posible .

Realmente no puede ocultar este nombre de usuario y contraseña que la aplicación utiliza para acceder a la base de datos. Por lo general se almacenan en una inio configarchivo, o posiblemente al horno en el ejecutable en sí. En todos los casos, son visibles para el usuario si cavan un poco. En un caso, en realidad utilizamos un configarchivo pero lo ciframos, pero, por supuesto, la clave de cifrado tenía que almacenarse en el archivo ejecutable (no éramos ingenuos ante las limitaciones de esto, pero efectivamente evitó que las personas hurgaran lo suficiente como para saberlo). para buscar en los configarchivos).

Todos estos sistemas tenían un sistema de autenticación de usuario integrado en la aplicación, pero, por supuesto, todos se gestionaron a través de la propia aplicación, lo que significa que la información del usuario se almacenó en la base de datos. La aplicación restringió las cosas que podría hacer en función de su nivel de acceso, pero es muy discutible si solo puede conectarse a la base de datos y ejecutar consultas ad-hoc.

Me interesa saber qué hacen otros sistemas para solucionar este problema. Estas son las opciones que conozco:

  1. Use el mecanismo de seguridad de SQL Server para mantener una lista de usuarios y roles, y hacer que la aplicación de escritorio agregue y elimine usuarios a través de consultas T-SQL.
  2. En lugar de conectarse directamente a la base de datos, cree algún tipo de servicio web que se ejecute en el servidor y coloque la lógica de autenticación allí. Haga que cada solicitud haga validación de seguridad.

Las primeras opciones son un poco feas porque separas a los usuarios de la base de datos, por lo que los usuarios ya no son entidades de primera clase y no puedes hacer referencia a ellos con relaciones de clave externa, etc.

El segundo parece ser un gran problema de rendimiento y mucho trabajo adicional, además de que no puedes usar fácilmente los mapeadores de ORM como NHibernate (creo).

¿Alguien tiene experiencia con esto? ¿Mejores prácticas?

Editar

Pensando un poco más, ¿puede la autenticación de SQL Server realmente resolver este problema? Por ejemplo, si su usuario debe poder insertar y actualizar los registros de la hoja de tiempo para que pueda editar su hoja de tiempo, no hay forma de que el servidor SQL pueda prohibir el acceso a otras filas en la tabla de detalles de la hoja de tiempo, lo que significa que también puede leer y escribir las hojas de tiempo de otras personas.

Scott Whitlock
fuente
Sobre el tema de los enlaces; No usar ORM como NHibernate es (creo) un problema. Si utiliza servicios web como ejemplo, encontrará muchas formas de vincular eficientemente sus datos a XML.
jasonk
De todos modos, no debería usar su ORM como un mapeo directo entre objetos comerciales y entidades de base de datos, es un enfoque deficiente que hace que las interfaces sean frágiles. Realice solicitudes a una capa empresarial que obtenga entidades de base de datos sin procesar y solo devuelva los datos requeridos al cliente.
gbjbaanb
@gbjbaanb: claro, cambiaré toda la arquitectura esta tarde. :)
Scott Whitlock
Supongo que podrías esperar hasta que alguien te piratee antes de cambiarlo, pero por el lado positivo, al menos no tendrás problemas para que tu jefe financie la reestructuración :-)
gbjbaanb
Puede evitar que un usuario actualice los registros de otra persona, utilizando un procedimiento almacenado como la única forma de actualizar los registros y utilizando el usuario que ejecuta el proceso como parte de la consulta. Ver CURRENT_USER
gbjbaanb

Respuestas:

9

Me temo que agregar una capa de servicio web es probablemente la solución correcta a su problema.

La separación del cliente de la implementación de la base de datos subyacente probablemente también lo ayudará a largo plazo.

Agregar una capa de servicio web no necesariamente tiene que afectar el rendimiento ...

De hecho, con una API adecuada, un servicio web puede mejorar el rendimiento, agrupando múltiples consultas de bases de datos dentro de la LAN del centro de datos, en lugar de requerir múltiples viajes de ida y vuelta a través de la WAN.

Y, por supuesto, una capa de servicio web a menudo se puede escalar horizontalmente y agregar el almacenamiento en caché adecuado a las consultas de su base de datos, tal vez incluso un mecanismo de notificación de cambio.

Una capa de servidor agrega seguridad que no puede garantizar con aplicaciones que se ejecutan en un cliente remoto. Todo lo que se ejecuta en un cliente puede ser "pirateado" y realmente no debe considerarse de ninguna manera confiable. Realmente solo debe poner la lógica de presentación en el cliente y alojar cualquier cosa importante en el hardware que tenga control completo.

No sé acerca de sus aplicaciones, pero mis aplicaciones web están naturalmente divididas en varias capas, con el código de presentación separado de la capa de persistencia por al menos un nivel de lógica empresarial que los mantiene separados. Creo que esto hace que sea mucho más fácil razonar sobre mi aplicación, y mucho más rápido para agregar o modificar la funcionalidad. Si las capas se separan de todos modos, es relativamente fácil mantener la capa de presentación en el cliente y el resto en un servidor bajo mi control.

Entonces, si bien puede resolver sus problemas sin introducir una capa de "servicio web", para cuando haya escrito todos los procedimientos almacenados (o equivalentes) necesarios para completar los huecos en la implementación estándar de seguridad de la base de datos, probablemente sería mejor escribir una aplicación del lado del servidor para la que puede escribir pruebas unitarias adecuadas.

Bill Michell
fuente
Admito que no tiene por qué ser un cuello de botella en el rendimiento, pero ciertamente agrega una capa adicional a la arquitectura, lo que significa mucho más mantenimiento.
Scott Whitlock
3
Agrega una capa, pero no necesariamente mantenimiento. Tenga en cuenta que con toda la lógica colocada en el servicio, no en el cliente, los cambios pueden 'implementarse' sin requerir que los usuarios actualicen sus aplicaciones cliente.
GrandmasterB
5

De manera similar a la respuesta de jmoreno, puede denegar el acceso de un usuario a todo, aparte de los permisos EXECUTE en los procedimientos almacenados, luego aprovechar el encadenamiento de propiedad para que el procedimiento almacenado realice las operaciones requeridas en las tablas.

Ver aquí para más detalles https://msdn.microsoft.com/en-us/library/bb669058(v=vs.110).aspx

Cuando el usuario ingresa su nombre de usuario / contraseña del lado del cliente, los almaceno y los envío como parámetros a cada llamada a un procedimiento almacenado. Luego puede verificarlos con los valores almacenados en una tabla antes de realizar la operación deseada.

Definitivamente no es la última palabra en seguridad, pero podría ser necesario si sus PC tienen inicios de sesión genéricos, lo que limita su capacidad de usar grupos AD para obtener permisos, o si tiene acceso limitado a AD.

James K
fuente
2

Un enfoque es usar grupos de AD y procedimientos almacenados para limitar lo que el usuario puede hacer; por ejemplo, su hoja de tiempo DB, podría permitir insertar, actualizar y eliminar las horas de los usuarios, pero no permitir la actualización de las horas de nadie más. El motor de la base de datos proporcionaría la identificación del usuario, el usuario no tendría acceso directo a las tablas de la base de datos, solo a los sp que realizaron consultas en función de su identificación de inicio de sesión.

Por supuesto, esto no siempre es factible, pero puede serlo. El mejor enfoque dependerá de sus requisitos y recursos.

jmoreno
fuente
Esto es algo que no había considerado. No estoy seguro de que sea una buena opción, pero funcionaría.
Scott Whitlock
1

Lo que insinúa como 'servicio web' se llama arquitectura de n niveles . En general, es el camino a seguir en los casos en que es probable que haya problemas de seguridad o configuración (por ejemplo, distribución de una aplicación en muchas oficinas). Sin embargo, no tiene que estar basado en la web. Muchos trabajan con otros protocolos.

Crea un servidor de aplicaciones para actuar como intermediario entre el cliente y la base de datos (y otros recursos). El servidor de aplicaciones maneja su autenticación basada en aplicaciones y realiza acciones en nombre del cliente. De hecho, idealmente no estaría haciendo ningún SQL en su cliente, sino que llama a métodos en el servidor de aplicaciones. El servidor de aplicaciones manejaría toda la manipulación de datos.

Hay una serie de beneficios para el enfoque. No necesita configurar conexiones de base de datos y controladores en clientes. No almacena usuarios de bases de datos, contraseñas y servidores. La configuración de los clientes ni siquiera es necesaria, solo apúntelos en código a la dirección o URL correcta. Además, con la 'lógica' en el servidor de aplicaciones, no tiene que repetirlo cuando desarrolla otras aplicaciones: los diferentes tipos de clientes pueden reutilizar el mismo servidor de aplicaciones.

Gran maestro B
fuente
Aún mejor, si (o cuando) alguien piratea sus escritorios (o servidor web en un equivalente basado en la web) el atacante puede tener acceso completo al sistema operativo, pero aún no tienen acceso a la base de datos. Por lo tanto, no pueden ejecutar "select * from users" canalizado a un archivo que se llevan, descifrar a su gusto y dejar que su CEO le explique a los medios por qué su sistema seguro se vio comprometido. Si también usa sprocs en la base de datos que solo permite el acceso de ejecución, entonces el atacante también puede hackear su servidor de aplicaciones y aún así no puede obtener toda su base de datos de usuarios.
gbjbaanb
1

La tecnología ha cambiado un poco. Si autentica a cada usuario en la base de datos y usa roles de base de datos, ahora puede usar lo que se llama una vista actualizable para resolver este problema, al menos en SQL Server.

Así es como se vería una vista actualizable para una tabla llamada SomeTabledonde cada fila de esa tabla está vinculada a un empleado. El empleado debería poder ver las filas vinculadas a ellos, y los miembros de la función de recursos humanos deberían poder ver todas las filas, por ejemplo:

CREATE VIEW [dbo].[vwSomeTable]
AS
    SELECT SomeTable.*
    FROM SomeTable
        INNER JOIN Employee ON SomeTable.Employee_ID = Employee.Employee_ID
    WHERE Employee.Username = USER_NAME() OR IS_MEMBER('HR_Role')=1

GO

Entonces, lo que debe hacer es otorgar permisos de lectura (y posiblemente escritura) en la vista ( vwSomeTable) a todos los usuarios, y no otorgar permisos en la tabla ( SomeTable).

Puedes probar esto así:

EXECUTE AS USER = 'Some_Regular_Username'
SELECT * FROM vwSomeTable

... que solo debería devolver sus filas. O:

EXECUTE AS USER = 'Some_HR_Username'
SELECT * FROM vwSomeTable

... que devolverá todas las filas. Tenga en cuenta que necesitará los permisos de ejecución como (suplantación) para hacer esta prueba.

Las vistas son actualizables, por lo que incluso el usuario normal puede hacer esto, siempre que la fila esté vinculada a su Employeefila:

UPDATE vwSomeTable
SET SomeColumn = 5
WHERE SomeTable_ID = 'TheID'
Scott Whitlock
fuente
0

El uso de la autenticación basada en certificados es la forma "correcta" de implementar una cuenta sql compartida. El objetivo es eliminar el uso de contraseña para este tipo de cosas.

Actualizar:

Supongo que entendió mal la pregunta. Pensé que tenía que ver con tratar de encontrar una alternativa a poner un nombre de usuario y contraseña de db en la configuración de una aplicación o respaldados en la aplicación misma.

Puede eliminar el problema de administrar las contraseñas en las aplicaciones mediante el uso de certificados del lado del cliente. El certificado en sí no es suficiente, debe tener un sistema de distribución y gestión capaz de realizar operaciones como la revocación del certificado.

Referencia: http://en.wikipedia.org/wiki/Public-key_infrastructure

dietbuddha
fuente
¿Puedes proporcionar más información sobre esto? Parece que podría ser ortogonal a la intención de mi pregunta original, pero es interesante.
Scott Whitlock
0

Al construir una nueva solución de seguridad de escritorio, optamos por la solución de servicio web que intentaré describir a continuación.

Compilamos los ejecutables de la aplicación de escritorio en un entorno separado de los desarrolladores. Y calcule un HASH a partir de ese ejecutable que se registra en la base de datos.

Un servicio web que proporciona toda la información necesaria para que se ejecute la aplicación, la contraseña de la base de datos, la información de la cadena de conexión, los permisos del usuario, etc.

Utilizamos el inicio de sesión único de DB por aplicación y registramos los detalles del usuario en la base de datos en las variables de sesión para poder auditar los registros.

Una DLL maneja toda la comunicación desde la aplicación de escritorio al servicio web, a la que solo se puede acceder con un token integrado en la DLL.

Para poder obtener la contraseña de la base de datos de la aplicación del servicio web, la DLL calcula el HASH de los llamadores de DLL en tiempo de ejecución y pasa como un parámetro al servicio web que valida el token de DLL y el tiempo de ejecución ejecutable calculó el HASH al registrado cuando se implementó (la aplicación solo está disponible en una única instalación compartida de red).

De esa forma, nos dimos cuenta de que es una buena solución al problema de seguridad que más nos preocupaba y que conocemos algunos defectos de diseño. Estamos casi terminando esta implementación y hasta ahora estamos contentos con los resultados.

Editar: puede reemplazar la idea de hash utilizando firmas digitales y certificados X.509.

Vitor Arbex
fuente
1
Parece bastante obvio dónde está el claro agujero de seguridad. La DLL de la que habla está en el sistema del cliente y no hay forma de que el código de su servidor verifique que está hablando de una copia legítima de la DLL o de una pirateada / maliciosa / falsa. Acaba de crear mucho trabajo para usted sin agregar mucha, si es que alguna, seguridad adicional. Todo lo que una persona maliciosa necesita es el token y el algoritmo, los cuales están en la DLL para cualquiera que quiera mirar.
Scott Whitlock
@ScottWhitlock, sí, estoy de acuerdo. estamos buscando ofuscar la DLL y el tráfico que pasa por HTTPS. Estamos tratando de mejorar eso, realmente me gustaría cualquier opinión sobre cómo mejorarlo. Pero esa solución ya resuelve muchos problemas que tiene el sistema actual, incluidas las contraseñas de texto sin formato almacenadas en archivos de red. Además, el servicio web permite la reutilización de una gran cantidad de código accesible por cualquiera de los idiomas del cliente que usamos aquí, ¡incluidos los clientes Delphi y Clipper (Harbor)!
Vitor Arbex
En su sistema, el usuario inicia sesión y es presumiblemente autenticado por el servicio web. Suponiendo el uso de HTTPS, ¿no es eso lo suficientemente bueno? No tiene que confiar en el software del cliente, ya que sabe que el usuario es quien dice ser y usted controla el servicio web, por lo tanto, asegúrese de que el servicio web solo entregue información que el usuario dado está autorizado a ver. Incluso si aplicaron ingeniería inversa al cliente y escribieron el suyo, ¿qué daño podrían hacer? Solo su servicio web conoce la contraseña de la base de datos, y eso debería ser seguro.
Scott Whitlock