24 mar 2012

Ataque XSS

Utilizando los dos post anteriores (Controlando el Control y Tiempo de Diseño en Controles) podemos ejemplificar como funciona unas las vulnerabilidades propias de las aplicaciones Web: el XSS  Cross-site scripting  (le ponen la x para que no se confunda con CSS).

El XSS consiste básicamente en inyectar javascript malicioso aprovechando las debilidades de los sitios que lo permitan, no se deben tomar a la ligera por cuanto puede llegar a se muy dañinos  Tomando como referencia la Wikipedia hay varias formas de llevar a cabo este tipo de ataque, pero para nuestro ejemplo nos centraremos en el ataque directo, que normalmente consiste en inyectar código en un textbox cuyo dato posteriormente se mostrará, por lo que al dibujar el contenido del control se convierte en un script que se ejecuta dentro de la pagina.

Tomemos la pagina de prueba de nuestro tutorial de creación de controles.


Como se puede apreciar consiste en un textbox, un botón y un label. Lo que escribimos en el TextBox al hacer clic sobre el Botón se mostrará en el Label. Imaginemos una pantalla donde el usuario digita algunos datos y otra donde estos se muestran solo como lectura, la mecánica es similar.

Que pasa si en la caja de textto incluimos algo como
<script>alert ('Vulnerablidad XSS'); </script>.

Así como esta nuestro control (sin utilizar un UpdatePanel) pasaría lo siguiente:
Como se puede ver el ASP.Net incorpora un mecanismo por medio del cual se validan las entradas que realizan los usuarios. Esta activada por defecto, pero es tan sencilla de deshabilitar, como agregar la directiva validateRequest="false" a la página o por medio del archivo de configuración para todo un sitio.

Supongamos que esta barrera esta de habilitada o que fue superada y el script logró ser introducido. ¿Que sucedería? Pues que nuestro label personalizado como cualquier Label de .Net se dibujará como un elemento HTML tipo span y el script inyectado se ejecutaría.


El riesgo es bastante alto. Imaginemos que el script ingresado hubiese sido:
while(1)alert("Este mensaje saldra indefinidamente");

El sistema ingresaría en ciclo infinito de mensajes. Por supuesto que hay script mucho más peligrosos, con fines más específicos, pero ha modo de ejemplo con esto basta para darnos cuenta que nuestro control, nuestro Label personalizado, debe contar con alguna forma de lidiar con este tipo de ataque.

La respuesta está en  HttpUtility.HtmlEncode del namespace System.Web, por medio de este prevenimos que elementos propios de script o manipulaciones de DOM como tratar de incluir iframes, divs, etc. se puedan ejecutar, ya que parsea los caracteres especiales en códigos html y al final los muestra como simple texto.

Al final del método Render de nuestro control personalizado, podemos modificar el finally para que quede de la siguiente manera
    finally
    {
        Text = HttpUtility.HtmlEncode(Text);
        base.Render(writer);
    }

Una vez hecho esto, ejecutamos de nuevo las pruebas de ataques XSS para demostrar que, por lo menos con esta ajuste, ya estamos mejor preparados.

Como desarrolladores de aplicaciones Web debe estar conscientes de la existencia de este tipo de ataques, para poder preparar nuestras aplicaciones para lidiar con ellos.

11 mar 2012

Tiempo de Diseño en Controles

Continuando con nuestro pequeño tutorial. del post anterior sobre la creacion de un custom server controls para ASP.Net vamos hablar del tiempo de diseño o modo de diseño.Nos referimos  a cuando usamos el diseñador de Visual Studio para colocar y modificar nuestros controles.

Cuando estamos trabajando en el diseñador con nuestros controles debemos estar consientes que éstos se muestran o dibujan utilizando el método Render del mismo. Hay casos en los que accedemos a variables o recursos que únicamente están disponibles en tiempos de ejecución. Esto puede provocar que el control no se pueda dibujar de forma correcta.

En el caso de nuestro tutorial. cuando cambiamos la propiedad DisplayFormat de nuestro Label personalizado por algún valor  distinto  a "NoFormat" se nos muestra la Exception tal y como esta previsto para el tiempo de ejecución en el método Render:

Para controlar este comportamiento se pueden emplear varias técnicas. La Primera y más natural es que la clase Control (de la que heredan los webcontrols como el Label o TextBox) expone la propiedad DesignMode.la cual es verdadera cuando se está en tiempo de diseño por lo cual es muy sencillo hacer lo siguiente:
protected override void Render(HtmlTextWriter writer)
{
    if (this.DesignMode)
    {
        //Estoy en tiempo de diseño
    }
        else
    {
        //Estoy en tiempo de Ejecución
    }
    base.Render(writer);
}

También se puede usar HttpContext.Current. Si éste se encuentra nulo entonces quiere decir que se esta en diseño. Por lo que se puede crear una variable booleana que verifique si es o no null de la siguiente manera
private bool inDesignMode = (System.Web.HttpContext.Current == null);

Y finalmente se puede usar igual que DesignMode del primer segmento de código. Aplicando esto a nuestro método Render nos quedaría de la siguiente manera
protected override void Render(HtmlTextWriter writer)
{ 
    try
    {
        if (inDesignMode)
        {
            _displayformat = DisplayFormat.NoFormat;
        }

        if (Text.Length > 0)
        {
            switch (_displayformat)
            {
                case (DisplayFormat.FinancialFormat):

                    Text = Text.Replace('(', '-').Replace(")", string.Empty);
                    string cerosdecimales = ConvertirACerosDecimales(_numeroDecimales);
                    decimal montotexto = Convert.ToDecimal(Text);
                    string formato = "{0:#,##" + cerosdecimales + ";(#,##" + cerosdecimales + ");0.00}";
                    this.Text = string.Format(formato, montotexto);
                    if (montotexto < 0)
                    {
                        this.ForeColor = System.Drawing.Color.Red;
                    }
                    break;
                case (DisplayFormat.MountFormat):
                    string formatoMonto = "{0:N" + _numeroDecimales.ToString() + "}";
                    Text = string.Format(formatoMonto, Convert.ToDecimal(Text));
                    break;
            }
        }       
    }
    catch (Exception ex)
    {
        Text = "Se ha producido un error aplicando el formato: " + ex.Message;
    }
    finally
    {
        base.Render(writer);
    }
}

Por lo que ya no importa cuando le cambiamos el valor a la propiedad DisplayFormat en el Diseñador siempre se mostrará el mismo diseño sin afectar el comportamiento real cuando se encuentre en tiempo de ejecución:

Otra cosa a tomar en cuenta en el tiempo de diseño es que ocasionalmente,.cuando se realizan cambios a controles que se encuentran dentro de un UpdatePanel y volvemos a la vista de diseño esta se puede desconfigurar mostrando una vista con un error similar al siguiente:

O ingles sería 'UpdatePanel' could not be set on property 'ContentTemplate' Cuando esto sucede lo que único que podemos hacer es cerrar el Visual Studio e ir a la ruta de de los archivos temporales (por lo general [WINDOWS]\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files) y borrar las carpetas de nuestros proyectos. Una vez hecho esto podemos reabrir Visual Studio y nuestra solución y el problema debería quedar resuelto.

3 mar 2012

Controlando el control

Vamos a hacer un control, uno sencillo. Se trata de un simple label para ASP.Net.

Primero añadimos un nuevo proyecto de biblioteca de clases. En mi caso decidí llamarlo foy.Web.Controles de manera que me quede de esa manera también, el namespace correspondiente. Seguidamente añadimos una clase que llamamos FoyLabel. Una vez añadida esta clase añadimos las referencias a System.Web y System.Drawing.

No vamos a partir de cero, si no, que vamos a implementar nuestro label a partir del Label de .Net

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace foy.Web.Controles
{
    public class FoyLabel: System.Web.UI.WebControls.Label
    {
        public FoyLabel()
            : base()
        {
        }
    }
}

Nuestro label personalizado, nos servirá tanto para mostrar texto normal o indefinido como para mostrar montos formateados.  Para Lograr este objetivo voy a usar un Enum que represente el tipo de formato que se desea asginarle al label. Luego creo una variable y una propiedad para asignar el tipo de formato al control. Asimismo deseo controlar la cantidad de decimales en caso de que el tipo de formato sea un monto
namespace foy.Web.Controles
{
    public enum DisplayFormat
    {
        ///    <summary>
        ///    Tipo de dato indefinido.</summary>
        NoFormat = 0,

        ///    <summary>
        ///    Tipo de dato caracter.</summary>
        MountFormat = 1,

        /// <summary>
        /// Formato financiero numeros negativos estan en rojo y entre parentesis
        /// </summary>
        FinancialFormat = 2
    }
    public class FoyLabel: System.Web.UI.WebControls.Label
    {
        #region Variables
        
        private DisplayFormat _displayformat;
        private int _numeroDecimales = 2;
        
        #endregion
        
        //constructor
        public FoyLabel()
            : base()
        {
        }

        #region Propiedades

        [Category("Layout"),
       DefaultValue(DisplayFormat.NoFormat),
       Description("Formatea el valor como monto si es necesario")]
        public DisplayFormat DisplayFormat
        {
            get
            {
                return _displayformat;
            }
            set
            {
                _displayformat = value;
            }
        }

        [Bindable(true),
      Category("Data"),
      Description("Número de decimales a mostrar cuando un numero se formatea"),
      DefaultValue(2)]
        public int NumeroDecimales
        {
            get
            {
                return _numeroDecimales;
            }
            set
            {
                _numeroDecimales = value;
            }
        }

        #endregion
    }
}

Una vez realizado Esto podemos sobre escribir el metodo Render para formatear el texto según el formato que se le haya asignado al control.
protected override void Render(HtmlTextWriter writer)
{
    try
    {
        if (Text.Length > 0)
        {
            switch (this.DisplayFormat)
            {
                case (DisplayFormat.FinancialFormat):

                    Text = Text.Replace('(', '-').Replace(")", string.Empty);
                    string cerosdecimales = ConvertirACerosDecimales(_numeroDecimales);
                    decimal montotexto = Convert.ToDecimal(Text);
                    string formato = "{0:#,##" + cerosdecimales + ";(#,##" + cerosdecimales + ");0.00}";
                    this.Text = string.Format(formato, montotexto);
                    if (montotexto < 0)
                    {
                        this.ForeColor = System.Drawing.Color.Red;
                    }
                    break;
                case (DisplayFormat.MountFormat):
                    string formatoMonto = "{0:N" + _numeroDecimales.ToString() + "}";
                    Text = string.Format(formatoMonto, Convert.ToDecimal(Text));
                    break;
            }
        }       
    }
    catch (Exception ex)
    {
        Text = "Se ha producido un error aplicando el formato: " + ex.Message;
    }
    finally
    {
        base.Render(writer);
    }

}

protected string ConvertirACerosDecimales(int numeroDecimales)
{
    string decimales = numeroDecimales == 0 ? string.Empty : ".";
    for (int i = 0; i < numeroDecimales; i++)
    {
        decimales = decimales + "0";
    }
    return decimales;
}

La función ConvertirACerosDecimales es utilitario para convertir la cantidad de decimales en string con los ceros que necesita el formato.

Ya con esto podemos probar el control. Creamos un sitio de prueba, añadimos a una página un Textbox, un Botón  y nuestro Label personalizado. La idea es que digitamos en el textbox y al hacer clic en el botón muestre en nuestro label el texto formateado.
<%@ Page Language="C#" Culture="en-US" UICulture="en-US" AutoEventWireup="true" CodeFile="TestControls.aspx.cs"
    Inherits="TestControls" %>

<%@ Register Assembly="foy.Web.Controles" Namespace="foy.Web.Controles" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Página de Prueba de Controles</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
    </div>
    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
    <br />
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <cc1:FoyLabel ID="LabelTest1" runat="server" DisplayFormat="FinancialFormat"></cc1:FoyLabel>
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="Button1" />
        </Triggers>
    </asp:UpdatePanel>
    </form>
</body>
</html>

Es importante registrar nuestro assembly con los controles por medio de la clausula @Register. En el code behind solo tenemos el evento del botón
protected void Button1_Click(object sender, EventArgs e)
{
    LabelTest1.Text = TextBox1.Text;
}

Probamos nuestra página .
Es importante señalar que por medio de la técnica de añadir un tipo Enum público como propiedad de un server control como en este caso se hizo con la propiedad DisplayFormat, los valores del enum quedan como valores elegibles en la propiedad desde el diseñador de Visual Studio:
Fin de este pequeño tutorial de creación de controles para ASP.Net