Inicio > .NET Framework, C#, Cómo hacer > Cómo ofuscar nuestras contraseñas

Cómo ofuscar nuestras contraseñas


Hola queridos amantes de la programación. En estos momentos me encuentro escribiendo la segunda parte del cuestionario sobre expresiones regulares. Pero no quería dejar pasar otro día sin compartir este pequeño consejo.

Sucede que cuando trabajamos en procesos de autenticación para nuestras aplicaciones muchas veces contamos con una tabla en una base de datos donde se guarda la información del usuario, así como su contraseña. Es una muy mala idea dejar las contraseñas así tal cual ya que si un atacante accede a nuestra base de datos, tendrá las contraseñas de todos los usuarios para hacer y deshacer el sistema a su antojo. Si bien el método más seguro sería encriptarlas (simétrica o asimétricamente) también es cierto que ésto conlleva complejidad ya que se requieren claves de encriptación que los usuarios deben conocer, o bien que deben ser estáticas y guardarse en el sistema de alguna forma. Así, en ocasiones no es posible realizar encriptación de las contraseñas. Pero debemos hacer un intento por ofuscarlas, cuando menos, para que sea difícil para el atacante obtenerlas.

Una primera aproximación para ello es codificar texto a base 64. Pero seamos honestos, esto sería muy ingenuo. Cualquiera que vea un texto con caracteres ininteligibles reconocerá el base 64 si ve caracteres = ó == al final de la cadena.

Pero podemos utilizar un algoritmo hash. .NET Framework, en su espacio de nombres System.Security.Cryptography nos provee de algunos algoritmos, como el MD 5 (clase MD5CryptoServiceProvider), el MD160 (RIPEMD160Managed), el SHA1 (SHA1CryptoServiceProvider) o el SHA256 (SHA256Managed). La forma de llevar a cabo esta ofuscación es la siguiente.

  1. Crear un objeto que represente algún algoritmo de hash.
  2. Guardar la contraseña como un array de bytes.
  3. Llamar al método ComputeHash del objeto del algoritmo y guardar el valor de retorno en lugar de la contraseña plana.
  4. Opcionalmente, la propiedad Hash de dicho objeto contendrá el hash utilizado, por si lo necesitas para algo más.

Como detalle adicional, dado que ComputeHash regresa un array de bytes, podemos convertirlo a su representación de texto en base 64. Ya no nos importa que sepan que es base 64 porque de todas formas estará hasheado, y el atacante no sabrá por dónde ir. Y si lo sabe, le tomará unos cuantos años averiguar la contraseña.

El siguiente ejemplo muestra lo anterior a través de un método que toma una contraseña, la ofusca y regresa su representación en base 64.

using System;
using System.Security.Cryptography;

static string ObfuscatePassword(string password)
{
  MD5 hash = new MD5CryptoServiceProvider();
  byte[] passwordBuffer = Encoding.UTF8.GetBytes(password);
  byte[] hashedPassword = hash.ComputeHash(passwordBuffer);
  string obfuscatedPassword = Convert.ToBase64String(hashedPassword);

  return obfuscatedPassword;
}

En la línea 6 creamos un objeto de algoritmo hash MD5, de los más básicos. Línea 7, codificamos la contraseña y la transformamos en bytes. Siguiente línea, aplicamos el hash sobre dichos bytes, y línea 9, convertimos dichos bytes a base 64.

Luego, cuando queramos validar al usuario solo tenemos que ofuscar la contraseña provista y compararla contra el valor previamente ofuscado: una simple comparación de texto bastará, dado que dos textos iguales regresan el mismo hash. Sirva el siguiente programa de ejemplo.

using System;
using System.Text;
using System.Security.Cryptography;

namespace Fermasmas.Wordpress.Com
{
  class Program
  {
    static string ObfuscatePassword(string password)
    {
      MD5 hash = new MD5CryptoServiceProvider();
      byte[] passwordBuffer = Encoding.UTF8.GetBytes(password);
      byte[] hashedPassword = hash.ComputeHash(passwordBuffer);
      string obfuscatedPassword = Convert.ToBase64String(hashedPassword);

      return obfuscatedPassword;
    }

    static void Main(string[] args)
    {
      string originalPassword = ObfuscatePassword("P@ssw0rd_123");
      Console.WriteLine("Hash de la contraseña original: {0}", 
          originalPassword);
      Console.WriteLine();

      ConsoleKey key = ConsoleKey.Q;
      do
      {
        Console.WriteLine();
        Console.WriteLine("Ingrese contraseña: ");
        
        string newPassword = ObfuscatePassword(Console.ReadLine());
        Console.WriteLine("Hash de la contraseña actual: {0}", newPassword);

        if (originalPassword == newPassword)
          Console.WriteLine("Acceso concedido...");
        else
          Console.WriteLine("Accesso denegado...");
        
        Console.WriteLine(
          "Presione cualquier tecla para continuar o 'Q' para terminar.");
        key = Console.ReadKey(true).Key;
      }
      while (key != ConsoleKey.Q);
    }
  }
}

Al correrlo, ingreso dos contraseñas inválidas y una tercera válida. Esta es la salida en la consola.

Hash de la contraseña original: lxCD4E8CcaDFA3M7017FwA==


Ingrese contraseña:
sorbetedelimon
Hash de la contraseña actual: 7vbXes/q8UMUylv34xop6A==
Accesso denegado...
Presione cualquier tecla para continuar o 'Q' para terminar.

Ingrese contraseña:
patatús
Hash de la contraseña actual: xpP+vt1fJz5OzX7DDyHyGA==
Accesso denegado...
Presione cualquier tecla para continuar o 'Q' para terminar.

Ingrese contraseña:
P@ssw0rd_123
Hash de la contraseña actual: lxCD4E8CcaDFA3M7017FwA==
Acceso concedido...
Presione cualquier tecla para continuar o 'Q' para terminar.

Eso es todo. Esta forma sencilla puede mejorar la seguridad de tu aplicación. Y también la puedes aplicar para cuando guardes información sensitiva en tus recursos o en tu web.config o app.config o cualquier otro archivo de configuración.

Categorías: .NET Framework, C#, Cómo hacer Etiquetas: ,
  1. No hay comentarios aún.
  1. No trackbacks yet.

Deja un comentario