Apuntes para una seguridad a nivel de usuario en Access 2010. Proteger el back-end
Las versiones de Access anteriores a la 2007 incluían un sistema de seguridad a nivel de usuario basado en grupos de trabajo bastante completo… salvo por el hecho de que, al menos en los últimos años, no servía absolutamente para nada. Resultaba del todo inútil identificar usuario y contraseña y asignar permisos en consecuencia si, con una sencilla búsqueda en interné, encontrábamos varias aplicaciones gratuitas con las que piratear las contraseñas. En consecuencia, en Access 2007 se abandona esta seguridad tan insegura.
A cambio, no se ha implementado ningún sistema de seguridad a nivel de usuario, aunque se afirma que la seguridad ha mejorado notablemente, pues ahora las bases de datos se pueden proteger por contraseña al tiempo que se cifran por un algoritmo muy seguro. A partir de ese cifrado con contraseña, cada uno debe implementar su propio sistema de seguridad por usuarios. También podríamos guardar los datos en SQL-Server o en Sharepoint, utilizar la seguridad de éstos y olvidarnos de crear la nuestra propia, pero esto a menudo no es asequible.
Con archivos accdb, que es de lo que vamos a tratar, una posibilidad interesante es crear un sistema basado en los eventos de datos de Access 2010, de esa manera la lógica de la seguridad se traslada al back-end y se centra en las tablas en vez de hacerlo en la aplicación que las maneja.
Pero, para que el sistema sea seguro, tenemos que conseguir que el back-end sea completamente inaccesible para quien no cuente con los permisos necesarios y que ello no le impida ser accesible desde el fornt-end. La solución para esto ya está estudiada y vale lo mismo para Access 2007 que para Access 2010; será de lo que tratemos en este artículo y dejaremos para otro posterior cómo usar las macros de eventos de datos de Access 2010 para asegurar nuestros datos y, en un tercero, veremos cón utilizar las macros de datos para hacer un archivo de seguimiento, un log, de los cambios en los datos del back-end.
Proteger el back-end en Access 2007/2010
A partir de Access 2007, si protegemos nuestros datos con una contraseña, quedan a buen recaudo, puesto que la contraseña es mucho más segura que en versiones anteriores y, además, los datos se cifran.
El problema está en cómo hacer que nuestra aplicación acceda a esos datos sin que la contraseña quede expuesta. Podemos evitar tener tablas vinculadas y abrir los recordsets de todos los objetos mediante código, pero eso resulta pesado y se pierde la sencillez, que es la principal ventaja de Access. Al vincular tablas de una BD protegida, Access pide la contraseña y la guarda en la propiedad Connect del objeto TableDef correspondiente a esa tabla, de manera que basta con leer la propiedad Connect de la tabla correspondiente para conocer la contraseña
Es lo que se plantea en este hilo en UtterAccess http://www.utteraccess.com/forum/Access-2007-security-t1242310.html&p=1243573#entry1243573 y ahí mismo proponen una solución que, aunque luego se complica, es bastante sencilla y es de la que partimos: Las tablas se vinculan sin contraseña, lo cual al intentar abrirlas produciría un error, pero al inicio de la aplicación creamos, mediante código en el que indicamos la contraseña, un recordset que se mantiene abierto toda la aplicación y, al quedar abierta la conexión con la BD protegida, es innecesario indicarle de nuevo la contraseña, por lo que podemos abrir las tablas vinculadas.
Ocurre algo parecido cuando utilizamos conexiones ODBC, que la contraseña se guarda y queda accesible, y la solución es la misma, no guardar la conexión con contraseña, abrir una conexión mediante código y mantenerla abierta durante toda la aplicación. En http://blogs.office.com/b/microsoft-access/archive/2011/04/08/power-tip-improve-the-security-of-database-connections.aspx, otra vez en guiri, nos cuentan cómo hacerlo.
El código puede hacerse inaccesible, por ejemplo, convirtiendo la aplicación en ACCDE y/o protegiendo a su vez, previamente, el proyecto VBA con otra contraseña. De esta manera, las tablas sólo se pueden abrir desde nuestra aplicación y, desde ella, controlamos quién y cómo puede acceder a los datos. Cualquiera podría importar nuestras tablas vinculadas desde otra BD, pero no sabiendo la contraseña, no le serviría de nada. También podría, si es un usuario autorizado, abrir directamente a las tablas de nuestra aplicación y saltarse así los permisos que damos mediante código, pero eso también podemos evitarlo, por ejemplo, comprobando que la aplicación se ejecuta en modo runtime justo antes de abrir el recordset que proporciana la clave al resto de la aplicación y, cuando sepamos asegurar los datos con macros de datos, ni siquiera podrán modicar nada sin permiso, aunque accedan a las tablas.
En resumen, los pasos para proteger nuestro back-end de una forma muy sencilla serían los siguientes:
1º- Vincular las tablas del back-end antes de cifrarlo con contraseña (de esa manera la contraseña no se guardará en la propiedad Connect)
2º – Cifrar con contraseña el back-end
3º – Al inicio de nuestra aplicación abrir un formulario invisible (o un módulo de clase) en el que asignaremos la contraseña mediante código, y que mantendrá abierta la conexión con el back-end durante toda la aplicación.
Este último punto puede parecer difícil, pero es sencillo haciéndolo de la siguiente manera:
- Vinculamos una tabla con datos irrelevantes. Nos pedirá contraseña y se guardará, pero más tarde la borraremos. Como ya existiría esa misma tabla vinculada, se guardará con el mismo nombre y un ordinal, por ejemplo TablaTonta1.
- A partir de la tabla recién vinculada, creamos el formulario con sus campos.
- Cambiamos la propiedad “Origen del registro” del formulario para dejarla en blanco.
- En el evento Load del formulario abrimos un recordset que tome los datos de la BD protegida y lo asignamos como recordset del formulario.
Private Sub Form_Load() Dim rs As DAO.Recordset Set rs = CurrentDb.OpenRecordset("SELECT TablaTonta.* FROM TablaTonta IN '' [MS Access;PWD=Anchoas de Santoña;DATABASE=C:UsersCheaDocumentsBack-end protegido.accdb]", dbOpenDynaset) Set Me.Recordset = rs End SubProbamos que el formulario se abre correctamente y cambiamos la propiead Visible del formulario a No. Hay un truco para obtener fácilmente una cadena SQL correcta que abra un recordset de una tabla en una BD externa protegida por contraseña:
-
-
- En el editor de VB abrimos la ventana de inmediato, decimos que nos imprima la propiedad Connect de la tabla que tenemos vinculada con contraseña y copiamos el texto de la propiedad connect al portapapeles
-
-
-
- Abrimos el asistente para consultas para crear una nueva consulta y, antes de añadir una nueva tabla, copiamos el texto de la propiedad Connect a la propiedad de la consulta Cadena de conexión de origen
-
-
-
- Añadimos ahora la tabla que queramos. Observe que lo que se muestra ahora son las tablas y consultas de la base protegida (Sí, he dicho consultas, se puede hacer un Select a una consulta de una BD externa)
- Seleccionamos los campos que queramos y copiamos el texto SQL resultante.
-
Con ese texto SQL podemos crear el recordset que asignaremos como origen de nuestro formulario.
-
- Borramos la tabla que acabamos de vincular con contraseña: Ya no la necesitas, la única mención a la contraseña que existe en nuestra aplicación está oculta en el código que asigna el recordset al formulario oculto.
Ya tenemos la manera de abrir una conexión con el back-end protegido que, permaneciendo abierta durante toda la aplicación, permita abrir otras tablas de ese back-end sin necesidad de indicar de nuevo la contraseña. Es decir, tenemos la llave para abrir los datos protegidos, sólo queda verificar el usuario antes de usar esa llave, por ejemplo, en el mismo formulario oculto, antes de asignar el recordset, podemos comprobar el usuario y sus permisos y, si no son los adecuados, en vez de asignar el recordset del formulario cerramos la aplicación. La manera de controlar usuario y permisos depende de cada cuál y no tiene mayor complicación, cuanto más personal sea, más segura, pero una forma muy sencilla podría ser tener una tabla con usuarios contraseñas y permisos en el back-end, con la que abriremos, mediante código, un recordset de la misma manera que hacíamos con la tabla tonta, para verificar los permisos, procurando primero haber borrado cualquier vínculo a la tabla.
Con estos sencillos pasos conseguimos que no se pueda acceder a nuestros datos directamente, sino solo a través de nuestra aplicación, de manera que podemos controlar quién y cómo lo hace. Es bastante seguro para lo fácil que resulta, pero en el propio hilo en UtterAccess que citábamos más arriba, advierten de posibles grietas y posibles soluciones.
La pega es que estamos protegiendo, o accediendo, a todo el archivo de back- end a la vez, y, si queremos dar permisos ppersonalizados por usuarios y tablas, debemos hacerlo por código, que sólo controla la edición de datos cuanto se hace a través de un formulario. El problema más obvio es que desde una instalación completa de Access, un usuario autorizado para abrir la aplicación puede pulsaf F11 para hacer que se muestren las tablas y editar los datos, saltándose todo el sistema de autorizaciones que hayamos implementado mediante código en los formularios.
Si estamos usando Access 2007, se me ocurre la solución de forzar a que la aplicación se ejecute en modo runtime, que no muestra las tabla; simplemente bastaría con verificar en el formulario de apertura si SysCmd(acSysCmdRuntime) es verdadero y, en caso contrario, cerrar la aplicación. Otra opción sería tener varios archivos de back-end agrupando las tablas por niveles de privilegios.
En cambio, si usamos Access 2010, cabe otra posibilidad, utilizar macros de datos en el back-end que comprueben los permisos del usuario antes de insertar, modificar o borrar datos en la tabla y, si carece de ellos, provocar un error que impida la actualización. Toda la lógica de la seguridad por usuarios se traslada al back-end, se centraliza y se hace más sencilla y, por tanto, más segura. De ello trataremos en un próximos artículo.
Lo que aquí se ha expuesto no es más que unos apuntes que puedan servir de punto de partida para que cada cual desarrolle su propio sistema de seguridad; no obstante, sin complicar demasiado las cosas, podemos tomar algunas medidas adicionales:
- Verificar que UserControl sea verdadero para evitar automatización
- Comprobar que CodeProject es el mismo que CurrentProject para evitar la carga como librería
- Proteger con contraseña el proyecto VBA y convertirlo en ACCDE.
- Sustituir el formulario por un módulo de clase en el que el recordset sea Friend.
- Ocultar las tablas utilizando el atributo dbHiddenObject.
En un próximo artículo veremos, cómo utilizando un back-end cifrado con contraseña, podemos valernos de las macros de eventos de datos de Access 2010 para impedir que un usuario no autorizado pueda insertar, modificar o borrar datos, incluso aunque tuviera acceso a las tablas vinculadas del front-ed.
2 Responsesso far
Después de casi dos años tomando impulso, por fin me animo a continuar con la seguridad
Muchas gracias por escribir este artículo