Blog Detail

hash_3b

Cifrado de contraseñas

28 Abr , 2016,
Jose Nunez
, , ,
No Comments

El tema de seguridad informática adquiere una relevancia exponencial en el advenimiento de la Internet de las Cosas, y de la cultura Maker; especialmente conforme comenzamos a desarrollar sistemas que realizan actividades más y más relevantes para el bienestar humano.

No son pocas las referencias de incidentes de seguridad de empresas de alto nivel tales como Sony, Linkedin y otros, que han sido víctimas del robo de datos de credenciales de usuarios; con el agravante de que, en numerosas ocasiones esas credenciales son utilizadas por los usuarios en multiples dominios; por ejemplo, el uso de una misma clave para varios sistemas (Facebook, Email, etc)

Este artículo tiene como objetivo explicar algunos procedimientos de uso común para el almacenamiento de contraseñas afin de reducir el riesgo de robo de credenciales para sus usuarios en sus aplicaciones IoT.

1. Teoría de “Hashing”

La palabra del Inglés “Hash” se traduce en español como “Picadillo”.

Este es el nombre de un procedimiento ampliamente usado para cifrar contraseñas que se deban almacenarse en los sistemas. Consiste en ejecutar un algoritmo matemático para convertir una contraseña (o cualquier texto legible) en otro cifrado que sea prácticamente único para esa contraseña.

Dentro de los algoritmos más confiables en la actualidad están el SHA1 o el SHA256. La característica principal de estos algoritmos es que para un texto legible dado (por ejemplo “mi contraseña”) al ejecutar el algoritmo para dicho texto, siempre va a resultar en un mismo texto cifrado, y que la mínima modificación del texto origen (por ejemplo “mi contrasena”) el resultado del algoritmo es extremadamente diferente. La otra caracterísitca importante es que el algoritmo descompone el texto legible inicial de forma tal que no hay forma matemática para re-componer el texto legible a partir del hash resultante.

Ejemplo:

SHA1("mi contraseña") ==> "823b57eb35f4e42e06a365d2af3cb6ebd6f9e89e"
SHA1("mi contrasena") ==> "6347b04dd43af8911075fc585d72f2fed320b264"

La forma en que se utiliza un mecanismo de hashing para almacenar contraseñas es que, en el sistema no se almacena la contraseña legible, sino su versión “hash”, y a la hora de autenticar un usuario, se toma la contraseña legible que este usuario suministra y se hace pasar por el proceso de hashing, luego se compara el hash almacenado con el hash de la contraseña suministrada para decidir si el usuario ingresó la contraseña correcta.

1.1 Debilidades

Si bien se ha mencionado que no existe forma matemática de re-componer un texto legible a partir de un hash, sí existen formas de conseguir:

(Caso a) el valor de la contraseña original si esta es demasiado simple, o

(Caso b) un valor que, pasado por el proceso de hashing, dé como resultado un valor hash predeterminado. A este proceso (caso b) se le llama “Colisión de hash” o “Hash Collision” que consiste en qué tan facil es encontrar dos valores que den como resultado un valor hash predeterminado. Para contrarrestar la debilidad  se debe utilizar un algoritmo de hashing suficientemente robusto respecto de la capacidad computacional actual. Por ejemplo, el algoritmo MD5 no se considera seguro por que es relativamente fácil con la capacidad computacional actual, encontrar colisiones para valores predeterminados de hash.

Cuando una contraseña es demasiado simple o predecible (caso a), puede encontrarse su valor de hash en tablas que se conocen como “rainbow tables”. A manera de ejemplo, basta con buscar en google el hash “7110eda4d09e062aa5e4a390b0a572ac0d2c0220” para ver los numerosos sitios de Internet que son capaces de determinar que corresponde a la clave “1234” usando el algoritmo SHA1

La siguiente figura explica el proceso de creacion de un hash.

hash_1b

2. Agregando algo de Sal

Para contrarrestar la existencia de tablas “rainbow” descritas anteriormente (caso a) se utiliza un mecanismo de seguridad adicional que se llama adición de sal  que consiste en agregar un valor aleatorio para cada contraseña a fin de que el valor hash resultante no coincida con ninguno en una tabla “rainbow”

En la siguiente sección explicamos el proceso de almacenamiento de “hash salados” y el proceso de comparación de una contraseña legible con estos hash a fin de determinar si la contraseña es correcta.

2.1 Almacenando contraseñas con hash salados

En el anterior apartado titulado “Teoría de Hashing” explicamos como el uso de una funcion SHA1 (u otro algoritmo de hashing) puede ser utilizado para generar códigos hash a partir de contraseñas legibles que se puedan almacenar, con ciertas limitaciones o debilidades inherentes a contraseñas demasiado sencillas o algoritmos demasiado fáciles de “hackear”.

El procedimiento de crear un “hash salado” a partir de una contraseña legible se puede enumerar en los siguientes pasos:

  1. Crear un hash simple a partir de la contraseña legible (   hash = sha1("1234");   )
  2. Generar un código aleatorio (sal) apto para criptografía*  (   sal = random_int(100000,999999);   )
  3. Concatenar la sal con el hash simple (  codigoSalado = sal + hash; )
  4. Generar un hash con base en los valores concatenados (   hashRobusto = sha1(codigoSalado);   )
  5. Concatenar nuevamente la sal con el nuevo hash para ser almacenado (   codigoParaAlmacenar = sal + hashRobusto; )
  6. Almacenar el valor del hash robusto con la sal  (   guardar (hashParaAlmacenar);

En la siguiente figura se ilustra el flujo de datos y procesos relacionados con el almacenamiento de contraseñas a través de hash salados.

hash_2d

2.2 Autenticación, comparando contraseñas legibles on hash salados almacenados

El procedimiento para autenticar un usuario respecto de una contraseña almacenada en la forma de un hash salado se puede describir como sigue:

  1. Generar un hash simple a partir de la contraseña suministrada  (   hash = sha1(contraseña);   )
  2. Obtener de la base de datos el hashRobusto y la sal correspondientes (   hashGuardado = obtenerHash (usuario);   )
  3. Descomponer la sal del hash robusto  (   sal = substr(hashGuardado, 0, 6);   hashRobustoAlmacenado = substr(hashGuardado,6);   )
  4. Concatenar la sal junto con el hash simple generado a partir de la contraseña suministrsada (   salYHash = sal + hash;   )
  5. Generar un hash robusto para la comparacion a partir de la concatenacion anterior (   hashParaComparar = sha1(salYHash);   )
  6. Realizar la comparacion de hashes (contraseñaValida =  hashParaComparar == hashRobustoAlmacenado; //comparación veradero/falso )

En la siguiente figura se ilustra el flujo de datos y procesos para la comparacion de contraseñas en un proceso de autenticación.

hash_2e

Conclusiones

Es imperativo no almacenar contraseñas legibles en los sistemas de informáticos, incluyendo IoT.

El uso de hash salados en el almacenamiento de contraseñas es una técnica ampliamente utilizada para minimizar los riesgos de robo de credenciales, el procedimiento es extremadamente sencillo y permite incrementar de manera significativa la seguridad de los sistemas.

¡No hay razón para hacerlo mal!


(*) Un valor aleatorio apto para criptografía es un número dificil de predecir. En general los números aleatorios generados por software se basan en listas predefinidas, que pueden ser más o menos predecibles.

848 total views, 1 views today

Leave A Comment