Grimpi IT Blog

marzo 26, 2009

Nueva versión de Open DBDiff

Filed under: Open DbDiff, SQL Server — Etiquetas: , — grimpi @ 1:41 am

Bueno gente, hay una nueva versión de Open DBDiff en la calle (o mejor dicho, en CodePlex).

Que es Open DBDiff?
Es un pequeño programa de sincronización de schemas de bases de datos que funciona en SQL Server 2005/2008.
Hay casi diria decenas de aplicaciones similares en el mercado. La gran mayoría, exceptuando Red Gate y un par más, son bastante limitadas y funcionan mal. No capturan todos los objetos de la base y son incapaces de generar un script que funcione cuando se presentan casos minimamente complejos.

Por otro lado, no existe ningún producto similar, que sea open source.
La idea de Open DbDiff es precisamente llenar este hueco. Hacer una herramienta de comparacion de schemas potente, facil de usar y 100% libre.

A futuro, planeo hacer lo mismo para MySql y a un futuro muy a largo plazo, Oracle.
Es capaz de generar un correcto script de sincronización en situaciones bastante extrañas. Despues de mas de un año de desarrollo, creo que la aplicacion evolucionó lo suficiente para ser probada seriamente en producción (aunque soy conciente de que todavia quedan algunos bugs por resolver).

Este es link a la home en CodePlex para quien le interese probarlo.

Anuncios

marzo 21, 2009

Diferencias entre TRUNCATE TABLE y DELETE FROM

Filed under: SQL Server, T-SQL — Etiquetas: , — grimpi @ 1:01 pm

Una duda bastante habitual entre los desarrolladores, es cuál es la diferencia entre un TRUNCATE TABLE y un DELETE FROM TABLE. Este post (y el blog en general) está centrado en SQL Server, sin embargo, la mayoría de las diferencias entre ambas sentencias aplican a cualquier motor de bases de datos (Oracle, MySQL, DB2, etc).
Primero voy a enumerar las diferencias y luego voy a explicar el porqué de dichas diferencias.

TRUNCATE TABLE

DELETE FROM

  • Es una operación DDL.
  • Es una operación DML.
  • No permite el borrado selectivo. TRUNCATE TABLE elimina todo el contenido de la tabla.
  • Permite el borrado selectivo, mediante la clausula WHERE.
  • No se puede ejecutar, si la tabla tiene asociadas, aun si no existiesen registros en la tabla que contiene la FK.
  • Se puede ejecutar si hay FK asociadas a la tabla, pero siempre y cuando no tenga registros asociados o la FK este deshabilitada.
  • Es la forma más rápida de eliminar el contenido de una tabla.
  • Es más lenta.
  • No se activa ningún trigger al ejecutarse (a partir de SQL Server 2005, es posible capturar el evento mediante un DDL trigger, pero a modo de auditoría, no es posible tener acceso a los valores que fueron eliminados).
  • Puede activarse el trigger de ON DELETE y poder determinar que registros están siendo eliminados. siendo eliminados.
  • En caso que la tabla tuviese un campo Identity, se resetea el valor a 1 (o al valor base determinado en el campo).
  • No resetea el valor del campo Identity, en caso que la tabla tuviese uno.
  • TRUNCATE TABLE desasocia (deallocate) las páginas de datos de la tabla.
  • DELETE FROM marca cada registro afectado, como eliminado.
  • El logueo en el transaction log es mínimo. Solo registra el dealloc de las páginas de datos.
  • Loguea cada operación sobre los registros afectados.
  • No puede ser ejecutado si la tabla tiene asociadas vistas indexadas.
  • Se puede ejecutar si la tabla tiene vistas indexadas.

Como podemos ver, TRUNCATE TABLE es bastante más restrictivo que DELETE, al punto que en muchas situaciones, aun si queremos eliminar todo el contenido de la tabla, no podemos hacerlo.

Ahora bien, que es lo que hace TRUNCATE y porque es mas rápido que su “competidor”?
Para eso primero voy a hacer una brevísima introducción a como almacena internamente SQL Server los datos.
En SQL Server, los registros de una tabla, son agrupados en una estructura física de datos, que se llama página. Cada página tiene un tamaño fijo de 8060 bytes, y puede almacenar uno o cientos de registros, dependiendo del tamaño del mismo. Cuando se intenta insertar más registros en una tabla y la página de datos está llena, se crea otra donde se inserta el nuevo registro y así sucesivamente.
El comando TRUNCATE, lo que hace es desasociar (deallocate) las páginas de datos de la tabla, sin alterar los registros en sí mismo, mientras que el DELETE FROM recorre cada uno de los registros y los marca como borrados, por lo tanto, hace muchas más operaciones de I/O, que aumenta exponencialmente en relación con TRUNCATE, a medida que aumenta el tamaño de la tabla.
Otra razón que explica la diferencia de performance, es que TRUNCATE TABLE solo loguea en el transaction log, el deallocate de las paginas con la tabla (por lo tanto, es posible hacer un rollback de un TRUNCATE, cosa que muchos piensan que no), mientras que el DELETE FROM manda al transaction log todos los registros afectados, lo que es obviamente mucho más costoso a nivel recursos de I/O.
Por último, al hacer un TRUNCATE un lockeo sobre la tabla, a diferencia del DELETE FROM que hace un lockeo por pagina o registro, el consumo de memoria para almacenar los objetos lockeados es mucho menor.

marzo 11, 2009

Como almacenar passwords en una base de datos?

Filed under: Arquitectura, Seguridad — Etiquetas: — grimpi @ 9:53 pm

Supongamos que tenemos que hacer el típico sistema donde el usuario se autentica contra una tabla de nuestra base de datos.
Entre todas las cuestiones de seguridad que hay que tener en cuenta, surge un problema muy común: De que manera almacenar el password de los usuarios en nuestra base de datos?

Existen 4 maneras clásicas de hacer esto:

  • Guardarlo así como viene, en un campo sin encriptar, como si fuera un campo de texto normal.
  • Guardarlo encriptado.
  • Aplicarle una función hash y guardar el hash del password.
  • Aplicarle una función hash + un salt y guardar el hash del password.

Password plano:

La primer opción, por obvias razones, es la más simple de todas, pero extremadamente insegura y salvo en sistemas donde la seguridad NO IMPORTE EN ABSOLUTO, no debe ser utilizada. Sin embargo no es infrecuente encontrar sistemas donde nadie se haya tomado la molestia al menos, de dificultar mínimamente el acceso al password.
Un argumento que se puede dar a favor de este enfoque, es que si el acceso a la base de datos y la tabla de usuarios, está correctamente configurado y restringido, no debería haber problemas de seguridad. Lo que es una mentira atroz, porque tanto el DBA como los desarrolladores, tendría potencialmente acceso a estos datos.
Y si un hacker termina rompiendo de alguna manera la seguridad de nuestra base de datos, podría llegar a leer sin ningún problema, el password de todos los usuarios.

Password encriptado reversible:

La segunda opción, consiste en encriptar el password. Es mejor que nada, pero tiene sus problemas. El primer inconveniente que surge con este enfoque, es donde guardar la llave de encriptación. En un archivo de configuración? De qué sirve usar el algoritmo de encriptación más complejo y seguro que exista, si luego guardamos la llave de encriptación, en un archivo plano o de fácil acceso?
Y el segundo problema de este enfoque, es que el password es reversible. Que significa esto? Que es posible obtener el password sin apelar a la fuerza bruta. Por lo tanto, una potencial debilidad.
Si se pueden desencriptar, el riesgo de que alguien conozca la llave y tenga acceso a todo el sistema con todos los usuarios es muy grande. En un organización para el programador/DBA resulta extremadamente fácil obtener el password de los usuarios del sistema que mantiene/desarrolla, ya que tiene acceso a las tablas y a la clave de encriptación.

Password encriptado irreversible:

Perfecto, ya vimos que las primeras 2 opciones, son bastante débiles. Qué hacemos?
La tercera manera de almacenar el password, es usar una función hash. Como es esto?
Una función hash, es una función que encripta un determinado texto de forma no reversible, esto significa que no existe forma de “desencriptar” dicho texto. Lo que es perfecto para almacenar password. En la tabla ahora tenemos que guardar el hash del password. Es un método mucho más seguro que los otros 2 anteriores. Al no poder ser “desencriptado” el password, no existe forma de obtenerlo.
Entonces, si no puedo desencriptar una contraseña, ¿Cómo puedo saber entonces si una contraseña entregada es válida? La respuesta es muy simple. Se encripta la contraseña entregada y se compara el resultado de la encriptación con la contraseña previamente almacenada.

CLAVE_HASH = FUNCION_HASH(Password)

Existen principalmente 2 algoritmos para hacer Hash: MD5 y SHA-1 (también existen variantes de este como el SHA-256 y SHA-512).
Sin embargo, existe una debilidad, veamos el siguiente ejemplo de una tabla Usuario:

ID Usuario Password
1 Pepe ADC2-1234….
2 Rosario ADC2-1234….
3 Juan FA3D-BC56….
4 Grimpi FFD3-D045….

Si somos observadores, el hash del password de los usuarios Pepe y Rosario son el mismo. No podemos saber cuál es el password exacto de ambos, pero si podemos saber que son iguales. Supongamos que nuestro sistema tiene 50000 usuarios. Cuál es la posibilidad de que existan passwords repetidos? Muy grande. Si un Hacker por alguna razón, obtiene el password de Pepe, instantáneamente, ya sabría cual es el password del usuario Rosario. Mala idea.
Por otro lado, este enfoque también tiene otro grave inconveniente, que son los diccionarios de claves hash (Rainbow tables). Un diccionario de estas características, no es más que una enorme tabla de 2 campos, donde en el primer campo figura la clave hash y en el segundo campo, el texto plano correspondiente a esa clave.
Los usuarios no suelen poner claves muy complejas a excepción que uno se lo exija, por lo tanto, un diccionario de claves hash muy amplio, seguramente contendrá la mayoría de las password de los usuarios.

Entonces, que hacemos?

Password encriptado irreversible + Salt:

Que es un salt?
Un salt no es ni mas ni menos que texto o un conjunto de caracteres que varían por usuario/registro que se le concadena al texto antes de ser encriptado por una función hash. Y para qué queremos hacer esto? Para evitar los problemas del enfoque anterior. Si a un password se le concadena un texto que varia por usuario, como por ejemplo, el ID del mismo o el login, el hash sería diferente aun si tuviésemos 2 o más usuarios con exactamente el mismo password.
Pero además, dificultamos enormemente el ataque del hacker usando un diccionario de claves. Por supuesto, que a medida que el Salt sea más complejo, más dificultosa será la tarea del hacker.

CLAVE_HASH = FUNCION_HASH(Password + Salt)

Existen básicamente 2 estrategias diferentes para determinar el salt de un password. Recordemos que a la hora de autenticar el password, debemos saber el valor del salt para generar una clave encriptada idéntica a la que tenemos en la base de datos.

La primera estrategia consiste en generar un texto aleatorio (convenientemente con caracteres “raros” para dificultar todavía más la tarea de un ataque por diccionario) y asociárselo al usuario, por lo tanto, sería necesario agregar un nuevo campo a la tabla de Usuarios, que tenga el valor del Salt:

ID Usuario Salt Password
1 Pepe AB_D!#$2 BFC3-8234….
2 Rosario T5&/021? AAC2-1290….
3 Juan ¿+}s34@” EC3D-4C56….
4 Grimpi D*-34r$Q AFC4-A145….

La otra estrategia consiste calcular el salt en función de algún dato del usuario, como por ejemplo el username (que se supone que debe ser único), el ID de la tabla o algún otro campo del mismo. La ventaja de esta estrategia es que no tenemos que agregar un nuevo campo a la tabla, pero debemos asegurarnos que usamos un valor univoco en toda la tabla!!.

Recomiendo ver este link con una interesante discusión que hubo en un foro, con respecto a las distintas maneras en que se puede obtener el valor salt y este paper que explica mejor el metodo recomendado.

Crea un blog o un sitio web gratuitos con WordPress.com.