lunes, febrero 23, 2009

Encriptación de imágenes/ficheros en servidor con asp.net

Las clases Crypto.cs y CryptoProvider.cs las podéis descargar desde aquí.

En este artículo vamos a explorar un aspecto que siempre me ha tenido preocupado a la hora de trabajar con imágenes o ficheros subidos por los usuarios en aplicaciones en internet con asp.net. El problema es la encriptación de esos archivos para evitar que alguna persona pueda linkarlos y acceder a ellos. 

La raiz del problema
Cuando programamos una aplicación ASP.NET para que se puedan subir archivos a una carpeta, debemos darle permiso al usuario con el que se ejecuta el proceso ASP.NET para que escriba en esa carpeta y para leer la información (para su poste
rior visionado). Una alternativa es realizar un impersonate sobre el proceso (algo que nunca me ha gustado). Otras alternativas que propone la gente es darles nombres extraños, ubicaciones extrañas, etc. pero no dejan de ser soluciones de ocultación que no solventan el problema. La alternativa que vamos a ver en este post es la de realizar una encriptación del fichero subido con el algoritmo AES-Rijndael de forma que aunque un potencial usuario malintencionado gane acceso al fichero subido, no sea capaz de averiguar su contenido.

Las dos partes del problema
La encriptación de ficheros en servidor tiene dos partes bien diferenciadas que tenemos que solventar:
  1. Encriptación al subir el fichero
  2. Desencriptación al vuelo al visionar/descargar el fichero sin dejar ninguna copia desencriptada en el servidor.
El flujo de información del proyecto es el siguiente:
















Vamos al lío, subiendo archivos al servidor...
La primera parte es subir archivos al servidor. Cada uno utilizará el método que quiera, yo he utilizado el componente FileUpload que viene con los controles de servidor. Cuando se pulsa el botón de subir el archivo, se ejecuta el siguiente código, en el que se realizan las siguientes acciones:
  • Se comprueba que la extensión sea pdf
  • Se comprueba que el tamaño no exceda los 10MB (estoy hay que configurarlo en el web.config para que el servidor lo admita)
  • Se sube el fichero con un nuevo nombre único
  • Se encripta el fichero

















La línea clave es objencriptador.EncriptarFichero(), ¿qué es lo que hace esta función? Esta función es la encargada de encriptar el fichero pasado en el primer parámetro, guardarlo con el nombre del segundo parámetro y eliminar el original.





















Este método se encuentra en una clase llamada Crypto.cs que utiliza otra llamada CryptoProvider.cs que se encarga de inicializar el proveedor de encriptación. Hay que tener en cuenta que el algoritmo Rijndael se basa en dos cadenas: la clave y el vector de inicialización. Ambos valores se guardan en el app.config de la clase de negocio o se codifican en la clase. Al inicializar el proveedor Rijndael, ambos valores son pasados a su constructor para que pueda encriptar y desencriptar.

En este método, lo que se hace es abrir dos streams, uno para la entrada y otro para la salida. Seguidamente se inicializa el proveedor de servicios de encriptación con la clave (Key) y el vector de inicialización (IV), en modo encriptación. Una vez inicializado, el siguiente paso es crear un stream encriptado para ir pasando del fichero de origen al destino. Pasamos la información de un fichero a otro a través del CryptoStream, cerramos todos los flujos y eliminamos el fichero original.

Ya está encriptado, ¿cómo lo ve el usuario?
Ya tenemos el fichero encriptado en el servidor, por lo que el siguiente paso será desencriptarlo cuando haya que hacerlo sin dejar copia en el servidor. Para ello nos vamos a crear una página aspx que devuelva un flujo desencriptado al explorador del usuario.










En el momento que queramos descargar/visualizar el fichero desencriptado, la página en la que nos encontremos invocará a la página ObtenerPDF.aspx que solicitará el fichero desencriptado a la clase Crypto.cs. Esta clase, devolverá un MemoryStream desencriptado que será devuelto al explorador del cliente (junto con las cabeceras necesarias) para que sea renderizado en pantalla.















En mi caso, miro el fichero a desencriptar de la sesión del usuario. Habría que comprobar la seguridad para evitar accesos indebidos. Una vez obtenido el fichero, invocamos al método DesencriptarFichero() de la clase Crypto, que devuelve un objeto del tipo MemoryStream. Ese objeto es devuelto en el Response de la página para que el cliente lo muestre en pantalla.

El método DesencriptarFichero realiza las operaciones inversas que se realizaron en el método de encriptación.





















Con esto tenemos ya listo nuestro sistema de encriptación/desencriptación de ficheros en servidor. Tened en cuenta que esta solución es para entornos de hosting remoto en los que no tenemos capacidad de tocar el sistema de archivos. Si el servidor es nuestro, existen otras alternativas como la reubicación en carpetas fuera del directorio web, u otras.

Conclusión
Como siempre, espero que os haya interesado este post. En este caso, el código que he puesto es solamente el de las clases Crypto y CryptoProvider. Cada caso es particular así que cada uno adaptará la solución a su entorno. En este artículo he intentado dar unas guías para que podáis de una forma "fácil" incluir la encriptación en vuestros desarrollos asp.net.