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

lunes, 12 de abril de 2010

Problemas de Reporting Services en IIS7, cambio idioma mensajes

Les comento unos problemas que se presentaron al colocar en producción algunos reportes de Reporting Services, el problema se manifiesta con problemas en el toolbar de los reportes (donde van los filtros) en donde no se muestra ninguna imagen de dicho toolbar.

El problema se da debido a las diferencias existentes en el nuevo core de IIS7 en donde existen cambios de arquitectura y hasta en los configs de las aplicaciones .NET. La sección que estaba debajo de se ha movido a debajo de

así que para que funcione en IIS deben colocar en el Config:

<system.webServer>
<handlers>
<add name="ReportViewerWebControl" path="Reserved.ReportViewerWebControl.axd" verb="*" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</handlers>
</system.webServer>

Link de donde saqué la información

Por otro lado si les interesa cambiar los mensajes predefinidos de Reporting Services (en Ingles), existe la alternativa de escribir una clase o dll y hacer referencia de el en el config.

Código Ejemplo:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Reporting.WebForms;
namespace NombreNameSpaceCompleto
{
public class CReportViewerCustomMessages :
Microsoft.Reporting.WebForms.IReportViewerMessages, IReportViewerMessages2
{
#region IReportViewerMessages Members
public string BackButtonToolTip
{get { return ("Página anterior"); }}
public string CurrentPageTextBoxToolTip

{get { return("Página actual"); }}
public string ExportButtonText

{get { return("Exportar"); }}
public string ExportButtonToolTip
{get { return ("Presione para Exportar"); }}
public string ExportFormatsToolTip
{get { return("Seleccione el formato para exportar"); }}
public string FalseValueText
{get { return("Falso"); }}

Y en el archivo de configuración se debe colocar en el AppSettings:

<add key="ReportViewerMessages" value="NameSpace.CReportViewerCustomMessages, NombreAssembly">

Por favor pongase en contacto si desea consultoría experta en Reporting Services integrado con ASP.NET.