miércoles, 28 de abril de 2010

Validaciones de contenido de archivo para subir a la WEB

En muchas aplicaciones se necesitan guardar archivos de los usuarios y en la mayoría de los casos se implementa una simple validación de extensión, pero un usuario malicioso podría subir archivos dañinos con extensiones falsas de los archivos que permite nuestra aplicación (ejm: imagenes, pdf, etc) con la esperanza que de alguna manera se ejecute el código malicioso del archivo subido.

Para proteger un poco mas nuestras aplicaciones podemos implementar una o dos barreras adicionales de protección: Validación de contenido y scan con antivirus. En este artículo hablare de la primera opción.

La idea e implementación es muy sencilla, basicamente lo que hay que hacer es que dependiendo de la extensión del archivo se chequea la cabecera/estructura del archivo para determinar si cumple o no con los estandares establecidos para el formato de archivo utilizado.

Por ejemplo un GIF debe comenzar con la cabecera GIF89a o GIF89a o PNG , para BMP los dos primero bytes son 0x42 0x4D, para PDF los primeros 5 bytes son %PDF-

Las validaciones pueden ser mucho mas complejas que solo la cabecera pero la cabecera es buen inicio ya que aunque el archivo maligno le coloquen la cabecera correspondiente a su tipo de archivo, el mismo hecho de modificar la cabecera para que cumpla el estandar dañara el código maligno o por lo menos la forma en que se ejecuta.

Ejemplo en código:

///
/// Valida si el contenido del archivo corresponde o no con el tipo de archivo que se indica solo para gif, jpg y pdf
///

///
El tipo de archivo indicado a validar///
La data del archivo/// Devuelve False si el contenido del archivo no coincide con el tipo de archivo
static private bool ValidarTipoArchivoContenido(string sTipoArchivo, byte[] Archivo)
{
bool bResultado = true;
try
{
int TamanoValidar = 0;
Stream objStream = new MemoryStream(Archivo);
switch (sTipoArchivo.ToLower())
{
case ".gif":
TamanoValidar = 6;
break;
case ".jpg":
case ".jpeg":
TamanoValidar = 4;
break;
case ".pdf":
TamanoValidar = 5;
break;
case ".bmp":
TamanoValidar = 2;
break;
case ".tiff":
case ".tif":
TamanoValidar = 4;
break;
case ".txt":
TamanoValidar = int.Parse(objStream.Length.ToString());
break;

}
if (TamanoValidar > 0)
{
bResultado = false;
byte[] Buffer = new byte[TamanoValidar];
objStream.Read(Buffer, 0, TamanoValidar);
objStream.Close();

string sCabecera = System.Text.Encoding.ASCII.GetString(Buffer);

switch (sTipoArchivo.ToLower())
{
case ".gif":
if (sCabecera == "GIF87a" || sCabecera == "GIF89a" || sCabecera.Substring(1, 3) == @"PNG")
bResultado = true;
break;
case ".jpg":
case ".jpeg":
if (int.Parse(Buffer.GetValue(0).ToString()) == 255 && int.Parse(Buffer.GetValue(1).ToString()) == 216 && int.Parse(Buffer.GetValue(2).ToString()) == 255 && (int.Parse(Buffer.GetValue(3).ToString()) == 224 || int.Parse(Buffer.GetValue(3).ToString()) == 225))
bResultado = true;
break;
case ".pdf":
if (sCabecera == "%PDF-")
bResultado = true;
break;
case ".bmp":
if (sCabecera == "BM")
bResultado = true;
break;
case ".tiff":
case ".tif":
if (sCabecera.Substring(0,2) == "II" && int.Parse(Buffer.GetValue(2).ToString()) == 42)
bResultado = true;
break;
}
}
}
catch (Exception ex)
{
bResultado = false;
log4net.LogManager.GetLogger("root").Error("Error validación contenido", ex);
}
return bResultado;
}

Esto es solo un ejemplo sencillo de implementación, si desea consultoría sobre el tema por favor contacteme

No hay comentarios.:

Publicar un comentario