Cómo: Proteger ASP.NET de los ataques de inyección

Mayo de 2005

Publicado: 21 de Diciembre de 2005

patterns & practices Developer Center (en inglés)

J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Andy Wigley
Microsoft Corporation

Este artículo se aplica a:
ASP.NET versión 1.1
ASP.NET versión 2.0

Resumen: En este artículo se describe cómo validar las entradas para proteger la aplicación de ataques de inyección. Realizar una validación de las entradas es esencial porque casi todos los ataques en el nivel de aplicación contienen entradas malintencionadas.
Se deben validar todas las entradas, incluyendo los campos de formulario, los parámetros de las cadenas de consulta y las cookies para proteger la aplicación frente a inyecciones de comandos malintencionados. Parata de la suposición de que todas las entradas realizadas a la aplicación Web son malintencionadas y asegúrese de utilizar la validación del servidor con todos los orígenes de las entradas. Utilice la validación del cliente para acortar los recorridos de ida y vuelta y mejorar la experiencia del usuario, pero no confíe en ella ya que no es muy segura.
Para validar entradas, defina las entradas aceptables en cada campo de entrada de la aplicación. Una práctica efectiva consiste en restringir la entrada en longitud, intervalo, formato y tipo. Utilice un método permisivo ("allow") para definir las entradas válidas en lugar de un método de denegación ("deny"). Este último tipo de método no es práctico ya que es muy difícil anticipar todas las posibles variaciones de entradas incorrectas.
Cuando sea necesario aceptar un rango de caracteres HTML, asegúrese de codificar como HTML los datos para que sean seguros antes de que se muestren como el resultado.

En esta página

Objetivos Objetivos
Descripción general Descripción general
Resumen de los pasos Resumen de los pasos
Paso 1. Uso de validaciones de solicitud de ASP.NET Paso 1. Uso de validaciones de solicitud de ASP.NET
Paso 2. Restricción de entradas Paso 2. Restricción de entradas
Paso 3. Codificación de resultados no seguros Paso 3. Codificación de resultados no seguros
Paso 4. Uso de parámetros de comandos para consultas SQL Paso 4. Uso de parámetros de comandos para consultas SQL
Paso 5. Comprobación de que no se devuelven errores ASP.NET al cliente Paso 5. Comprobación de que no se devuelven errores ASP.NET al cliente
Recursos adicionales Recursos adicionales
Comentarios Comentarios
Soporte técnico Soporte técnico
Comunidad y grupos de noticias Comunidad y grupos de noticias
Colaboradores y revisores Colaboradores y revisores

Objetivos

  • Restringir la entrada en longitud, intervalo, formato y tipo.

  • Aplicar la validación de solicitudes de ASP.NET durante el desarrollo para identificar ataques de inyección.

  • Restringir las entradas utilizando los controles del validador de ASP.NET.

  • Codificar los resultados que no sean seguros.

  • Ayudar a evitar la inyección SQL utilizando parámetros de comando.

  • Evitar que se devuelva información detallada sobre errores al cliente.

Descripción general

Es necesario validar todas las entradas no seguras a la aplicación. Debe dar por sentado que todas las entradas de los usuarios son malintencionadas. Las entradas de usuario en la aplicación Web incluyen campos de formularios, cadenas de consulta, cookies del cliente y valores de entorno del explorador como cadenas User-Agent y direcciones IP.

Una validación de entradas débil supone una vulnerabilidad frecuente que podría hacer que la aplicación fuese susceptible de recibir ataques de inyección. A continuación se muestran tipos habituales de ataque que se aprovechan de una validación de entradas débil o inexistente:

  • Inyección SQL. Si genera consultas SQL dinámicas basadas en las entradas del usuario, un intruso podría inyectar comandos SQL malintencionados que la base de datos podría ejecutar.

  • Secuencias de comandos entre sitios. Los ataques de secuencias de comandos entre sitios (XSS) se aprovechan de las vulnerabilidades en la validación de páginas Web mediante la inyección de código de secuencias de comandos del cliente. A continuación, este código se envía al equipo de un usuario desprevenido y se ejecuta en el explorador. Puesto que el explorador descarga el código de secuencias de comandos de un sitio de confianza, no puede determinar si el código es legítimo.

  • Acceso no autorizado a archivos. Si el código acepta entradas del autor de una llamada, un usuario malintencionado podría manipular potencialmente las operaciones del archivo del código, como el acceso a un archivo al que no deberían tener acceso o inyectar datos erróneos para aprovecharse del código.

    Nota: Los ataques de inyección funcionan en conexiones HTTP y HTTPS Secure Socket Layer (SSL). El cifrado no constituye una defensa.

A continuación se resume el método general para la validación de entradas. Deber aplicar este método a todas las entradas procedentes de la red, como cuadros de texto y otras entradas de campos de formularios, parámetros de cadena de consulta, cookies, variables del servidor y parámetros del método Web. Tenga en cuenta que la estrategia es, en primer lugar, permitir sólo las entradas correctas y, a continuación, rechazar las incorrectas. El motivo es que se pueden definir fácilmente las entradas correctas de la aplicación, pero no se puede anticipar el formato de todas las entradas incorrectas.

Para comprobar las entradas válidas, haga lo siguiente:

  • Restricción: compruebe si los datos son buenos al validar el tipo, la longitud, el formato y el intervalo. Para restringir las entradas de los controles del servidor, utilice los controles del validador de ASP.NET. Para restringir las entradas de otros orígenes, utilice expresiones regulares y una validación personalizada.

  • Rechazo: busque los datos que sabe que son incorrectos y rechace las entradas incorrectas.

  • Saneamiento: a veces también es necesario sanear las entradas y hacer que las entradas potencialmente malintencionadas sean seguras. Por ejemplo, si la aplicación admite campos de entrada de formato libre, como campos de comentarios, tal vez deba permitir ciertos elementos HTML seguros, como <b> e <i> y eliminar el resto de elementos HTML.

Resumen de los pasos

Para proteger a la aplicación ASP.NET de ataques inyección, realice los siguientes pasos:

  • Paso 1. Uso de validaciones de solicitud de ASP.NET.

  • Paso 2. Restricción de entradas.

  • Paso 3. Codificación de resultados no seguros.

  • Paso 4. Uso de parámetros de comandos para consultas SQL.

  • Paso 5. Comprobación de que no se devuelven errores ASP.NET al cliente.

En los siguientes apartados se describen todos los pasos.

Paso 1. Uso de validaciones de solicitud de ASP.NET

De forma predeterminada, la validación de solicitudes de las versiones 1.1 y 2.0 de ASP.NET detecta cualquier elemento HTML y caracteres reservados en los datos enviados al servidor. De este modo se ayuda a evitar que los usuarios inserten secuencias de comandos en la aplicación. La validación de solicitudes contrasta todos los datos de entrada con una lista no modificable de valores potencialmente peligrosos. Si se produce una coincidencia, devuelve una excepción del tipo HttpRequestValidationException.

Puede deshabilitar la validación de solicitudes en el archivo de configuración Web.config de la aplicación si agrega un elemento <pages> con validateRequest="false" o en una página individual si establece ValidateRequest="false" en el elemento @ Pages.

Si necesita deshabilitar la validación de solicitudes, se recomienda hacerlo sólo en la página afectada. Un ejemplo de esto puede ser una página con un campo de texto de formato libre que acepta entradas con formato HTML.

Confirmación de que la validación de solicitudes de ASP.NET está habilitada en Machine.config

ASP.NET habilita la validación de solicitudes de forma predeterminada. Puede ver la siguiente configuración predeterminada en el archivo Machine.config.comments.

<pages validateRequest="true" ... />

Para confirmar que no ha deshabilitado la validación de solicitudes, omita los valores predeterminados en el archivo Machine.config del servidor o en el archivo Web.config de la aplicación.

Prueba de la validación de solicitudes de ASP.NET

Es posible probar los efectos de la validación de solicitudes. Para ello, cree una página ASP.NET en la que, a fin de que la validación esté deshabilitada, debe establecer ValidateRequest="false" del siguiente modo.

<%@ Language="C#" ValidateRequest="false" %>
<html>
 <script runat="server">
  void btnSubmit_Click(Object sender, EventArgs e)
  {
    // If ValidateRequest is false, then 'hello' is displayed
    // If ValidateRequest is true, then ASP.NET returns an exception
    Response.Write(txtString.Text);
  }
 </script>
 <body>
  <form id="form1" runat="server">
    <asp:TextBox id="txtString" runat="server" 
                 Text="<script>alert('hello');</script>" />
    <asp:Button id="btnSubmit" runat="server" OnClick="btnSubmit_Click" 
                 Text="Submit" />
  </form>
 </body>
</html>

Cuando se ejecute la página, se mostrará "hello" en un cuadro de mensaje porque la secuencia de comandos de txtString se pasa y se procesa como una secuencia de comandos del cliente en el explorador.

Si establece ValidateRequest="true" o quita el atributo de página ValidateRequest, la validación de solicitudes de ASP.NET rechaza la entrada de la secuencia de comandos y dará un error como éste.

A potentially dangerous Request.Form value was detected from the client (txtString="<script>alert('hello...").

Nota No debe confiar en la validación de solicitudes de ASP.NET. Considérela una medida de precaución adicional a su propia validación de entradas.

Paso 2. Restricción de entradas

Para restringir entradas, siga estas instrucciones:

  • Utilice la validación de entradas del servidor. No confíe en la validación del cliente porque no es muy segura. Utilícela junto a la validación del servidor para acortar recorridos de ida y vuelta al servidor y mejorar la experiencia del usuario.

  • Valide la longitud, el intervalo, el formato y el tipo. Asegúrese de que las entradas cumplen las directrices que ha definido para entradas correctas conocidas.

  • Utilice tipos de datos sólidos. Asigne valores numéricos a tipos de datos numéricos como Integer (entero) o Double (doble). Asigne valores de cadena a tipos de datos de cadena. Asigne fechas al tipo de datos DateTime.

En aplicaciones de formularios Web que obtengan entradas a través de los controles del servidor, utilice los controles del validador ASP.NET para restringir las entradas. En el caso de otros orígenes de datos de entrada, como cadenas de consultas, cookies y encabezados HTTP, utilice la clase Regex del espacio de nombres System.Text.RegularExpressions para restringir las entradas.

Comprobación explícita de entradas de campos de formulario

Para restringir las entradas de los campos de formulario a través de los controles del servidor, puede utilizar los siguientes controles del validador de ASP.NET:

  • RegularExpressionValidator. Utilice este control para restringir la entrada de texto.

  • RangeValidator. Utilice este control para comprobar los intervalos de entradas numéricas, de moneda, de fechas y de cadenas.

  • CustomValidator. Utilice este control para la validación personalizada, como por ejemplo asegurarse de que una fecha se encuentre en el futuro o en el pasado.

Para validar la entrada de los campos de formularios recibidos a través de controles de entrada HTML, lleve a cabo una validación en el código del servidor y utilice la clase Regex para restringir la entrada de texto. En los siguientes apartados se describe cómo restringir una serie de tipos de entrada habituales.

Validación de campos de texto

Para validar campos de texto, como nombres, direcciones o números de identificación de impuestos, utilice expresiones regulares para hacer lo siguiente:

  • Restringir el intervalo aceptable de caracteres de entrada.

  • Aplicar reglas de formato. Por ejemplo, los campos basados en patrones, como el número de identificación para impuestos o los códigos postales, precisan de patrones de caracteres de entrada específicos.

  • Comprobar longitudes.

Uso de RegularExpressionValidator

Para utilizar un control RegularExpressionValidator, establezca las propiedades ControlToValidate, ValidationExpression y ErrorMessage en los valores adecuados, tal y como se muestra en el siguiente ejemplo.

<form id="WebForm" method="post" runat="server">
  <asp:TextBox id="txtName" runat="server"></asp:TextBox>
  <asp:RegularExpressionValidator id="nameRegex" runat="server" 
        ControlToValidate="txtName" 
        ValidationExpression="^[a-zA-Z'.\s]{1,40}$" 
        ErrorMessage="Invalid name">
  </asp:regularexpressionvalidator>
</form>

La expresión regular utilizada en el ejemplo de código anterior limita un campo de nombre de entrada a caracteres alfabéticos (mayúsculas y minúsculas), espacios, apóstrofes para nombres como O'Dell y el punto. Además, el campo está restringido a 40 caracteres.

Nota

Si el usuario no lo ha hecho, el control RegularExpressionValidator agrega automáticamente un signo de intercalación (^) y uno de dólar ($) como delimitadores de comienzo y fin de las expresiones. Se aconseja agregarlos a todas las expresiones regulares. Si se acota la expresión con los delimitadores, se asegura de que la expresión está compuesta únicamente por el contenido deseado.

Uso de la clase Regex

Si no está utilizando controles del servidor (lo que implica que no puede utilizar los controles del validador) o necesita validar la entrada de orígenes que no sean los campos de formulario (como parámetros de cadenas de consultas de formulario o cookies), puede utilizar una clase Regex.

Para utilizar la clase Regex

  1. Agregue una instrucción using para hacer referencia al espacio de nombres System.Text.RegularExpressions.

  2. Asegúrese de que la expresión regular esté dentro de los caracteres de anclaje ^ y $ (comienzo y fin de la cadena).

  3. Llame al método IsMatch de la clase Regex, tal y como se muestra en el siguiente ejemplo de código.

// Instance method:
Regex reg = new Regex(@"^[a-zA-Z'.\s]{1,40}$");
Response.Write(reg.IsMatch(txtName.Text));

// Static method:
if (!Regex.IsMatch(txtName.Text,@"^[a-zA-Z'.\s]{1,40}$")) 
{
  // Name does not match expression
}

Si no puede guardar en la caché la expresión regular para usarla con frecuencia, se recomienda que utilice el método IsMatch estático siempre que sea posible, por motivos de rendimiento, para evitar la innecesaria creación de objetos.

Validación de campos numéricos

En la mayoría de los casos, se debe comprobar el tipo y el intervalo de los campos numéricos. Para validar el tipo y el intervalo de un campo de entrada numérico que utilice un control del servidor, puede utilizar un control RangeValidator. El control RangeValidator admite tipos de moneda, fechas, números enteros, dobles y datos de cadenas.

Para utilizar un control RangeValidator, establezca las propiedades ControlToValidate, Type, MinimumValue, MaximumValue y ErrorMessage en los valores adecuados, tal y como se muestra en el siguiente ejemplo.

<asp:RangeValidator 
       ID="RangeValidator1" 
       Runat="server" 
       ErrorMessage="Invalid range. Number must be between 0 and 255."
       ControlToValidate="rangeInput" 
       MaximumValue="255" 
       MinimumValue="0" Type="Integer" />

Si no está utilizando un control del servidor, puede validar un intervalo numérico convirtiendo el valor de entrada en un número entero y, a continuación, realizando una comprobación de intervalo. Por ejemplo, para validar un número entero, convierta el valor de entrada en una variable del tipo System.Int32. Para ello utilice el nuevo método Int32.TryParse (introducido en la versión 2.0 de Microsoft .NET Framework). Este método devuelve false si se produce un error en la conversión de tipos.

Int32 i;
if (Int32.TryParse(txtInput.Text, out i) == false)
{
  // Conversion failed
}

Si está utilizando una versión anterior de .NET Framework, puede utilizar Int32.Parse o Convert.ToInt32 dentro de un bloque try/catch y controlar las excepciones del tipo FormatException que se generen si el valor de entrada no es del tipo correcto.

En el siguiente código se muestra cómo llevar a cabo una comprobación de tipo e intervalo de un número entero introducido a través de un control de entrada de texto HTML.

<%@ Page Language="C#" %>

<script runat="server">

  void Page_Load(object sender, EventArgs e)
  {
    if (Request.RequestType == "POST")
    {
      int i;
      if (Int32.TryParse(Request.Form["integerTxt"], out i) == true)
      {
        // TryParse returns true if the conversion succeeds
        if ((0 <= i && i <= 255) == true)
        {
          Response.Write("Input data is valid.");
        }
        else
          Response.Write("Input data is out of range");
      }
      else
        Response.Write("Input data is not an integer");
    }
  }
   
</script>

<html>
  <body>
    <form id="form1" action="NumericInput.aspx" method="post">
      <div>
        Enter an integer between 0 and 255:
        <input name="integerTxt" type="text" />
        <input name="Submit" type="submit" value="submit" />
      </div>
    </form>
  </body>
</html>

Validación de campos de datos

Es necesario validar que los campos de fecha sean del tipo correcto. En la mayoría de los casos, también es necesario comprobar el intervalo, por ejemplo para validar que estén en el futuro o en el pasado. Si utiliza un control del servidor para capturar una fecha de entrada y si además necesita validar que esa fecha esté dentro de un intervalo específico, puede utilizar un control RangeValidator con el campo Type ajustado en Date. Este control permite especificar un intervalo utilizando valores de fecha constantes. Si necesita validar un intervalo de fechas en función de la fecha actual, por ejemplo, para validar que la fecha esté en el futuro o en el pasado, puede utilizar un control CustomValidator.

Para utilizar un control CustomValidator y validar una fecha, establezca las propiedades ControlToValidate y ErrorMessage y el evento OnServerValidate para que apunten a un método personalizado que contenga la lógica de validación. En el siguiente código de página .aspx de ejemplo se refleja este enfoque.

<%@ Page Language="C#" %>

<script runat="server">

 void ValidateDateInFuture(object source, ServerValidateEventArgs args)
 {
   DateTime dt;

   // Check for valid date and that the date is in the future
   if ((DateTime.TryParse(args.Value, out dt) == false) || 
       (dt <= DateTime.Today))
   {
     args.IsValid = false;
   }
 }

</script>

<html>
  <body>
    <form id="form1" runat="server">
      <div>
        <asp:Label ID="Label1" Runat="server" 
                   Text="Future Date:"></asp:Label>
        <asp:TextBox ID="futureDatetxt" Runat="server"></asp:TextBox>
        <asp:CustomValidator 
              ID="CustomValidator1" Runat="server" 
              ErrorMessage="Invalid date. Enter a date in the future."
              ControlToValidate="futureDatetxt"  
              OnServerValidate="ValidateDateInFuture">
        </asp:CustomValidator>
        <br />
        <asp:Button ID="submitBtn" Runat="server" Text="Submit"  />
      </div>
    </form>
  </body>
</html>

Nota: El código anterior utiliza DateTime.TryParse, que es una de las novedades de .NET Framework 2.0.

Saneamiento de campos de texto libre

Para sanear las entradas, evite que se traten como código las entradas que no sean de confianza y, de esa forma, hacer que sean seguras. Por ejemplo, si la aplicación controla entradas de usuario que no pueden restringir o leer datos de una base de datos compartida, tal vez necesite sanear los datos o hacer que el resultado sea seguro cuando lo escriba en la página. Sanee los datos antes de la salida utilizando HttpUtility.HtmlEncode.

Habilitación de entradas HTML restringidas

Si la aplicación necesita aceptar un intervalo de elementos HTML, por ejemplo, a través de un campo de entrada de texto enriquecido como un campo de comentarios, desactive la validación de solicitudes de ASP.NET y cree un filtro que permita sólo los elementos HTML que desee que la aplicación acepte. Una práctica habitual consiste en restringir el formato a elementos HTML seguros como <b> (negrita) e <i> (cursiva). Antes de escribir los datos, codifíquelos como HTML. De este modo, las secuencias de comandos malintencionadas pasarán a ser seguras ya que se tratarán como texto y no como código ejecutable.

Para permitir entradas HTML restringidas

  • Agregue el atributo ValidateRequest="false" a la directiva @ Page con el fin de deshabilitar la validación de solicitudes de ASP.NET.

  • Codifique la entrada de cadenas con el método HtmlEncode

  • Utilice un control StringBuilder y llame al método Replace para quitar de forma selectiva la codificación de los elementos HTML que desee permitir

En el siguiente código de página .aspx se refleja este enfoque. La página deshabilita la validación de solicitudes de ASP.NET al establecer el valor ValidateRequest="false". Codifica la entrada como HTML y permite de forma selectiva los elementos HTML <b> e <i> a fin de permitir el formato de texto sencillo.

<%@ Page Language="C#" ValidateRequest="false"%>

<script runat="server">

  void submitBtn_Click(object sender, EventArgs e)
  {
    // Encode the string input
    StringBuilder sb = new StringBuilder(
                            HttpUtility.HtmlEncode(htmlInputTxt.Text));
    // Selectively allow  and <i>
    sb.Replace("&lt;b&gt;", "<b>");
    sb.Replace("&lt;/b&gt;", "");
    sb.Replace("&lt;i&gt;", "<i>");
    sb.Replace("&lt;/i&gt;", "");
    Response.Write(sb.ToString());
  }
</script>

<html>
  <body>
    <form id="form1" runat="server">
      <div>
        <asp:TextBox ID="htmlInputTxt" Runat="server" 
                     TextMode="MultiLine" Width="318px"
                     Height="168px"></asp:TextBox>
        <asp:Button ID="submitBtn" Runat="server" 
                     Text="Submit" OnClick="submitBtn_Click" />
      </div>
    </form>
  </body>
</html>

Validación de valores de cadenas de consulta

Valide los valores de cadenas de consulta de longitud, intervalo, formato y tipo. Normalmente esta validación se realiza mediante una combinación de expresiones regulares para:

  • Restringir los valores de entrada.

  • Establecer comprobaciones explícitas de intervalos.

  • Especificar las comprobaciones explícitas de tipos llevadas a cabo mediante la conversión del valor de entrada en su tipo de .NET Framework equivalente y el control de los errores de conversión que se produzcan.

En el siguiente código de ejemplo se muestra cómo utilizar la clase Regex para validar una cadena de nombre pasada en una cadena de consulta.

void Page_Load(object sender, EventArgs e)
{
  if (!System.Text.RegularExpressions.Regex.IsMatch(
       Request.QueryString["Name"], @"^[a-zA-Z'.\s]{1,40}$"))
    Response.Write("Invalid name parameter");
  else
    Response.Write("Name is " + Request.QueryString["Name"]);
}

Validación de valores de cookie

Un cliente puede manipular fácilmente los valores mantenidos en las cookies, como por ejemplo parámetros de cadenas de consultas. Los valores de las cookies se validan del mismo modo que los parámetros de cadenas de consulta. Se valida la longitud, el intervalo, el formato y el tipo.

Validación de rutas URL y de archivos

Si la aplicación tiene que aceptar entradas de nombres de archivo, rutas de archivo o rutas URL, debe validar que la ruta tenga el formato correcto y que apunte a una ubicación válida dentro del contexto de la aplicación. Si no se hace esto, los intrusos podrían convencer a la aplicación para que les dé acceso a ciertos recursos y archivos.

Validación de rutas de archivo

Para evitar que los usuarios malintencionados manipulen las operaciones del archivo del código, evite escribir código que acepte entradas de rutas o archivos proporcionados por el usuario. Por ejemplo:

  • Si tiene que aceptar nombres de archivo como entrada, utilice el nombre completo del archivo mediante System.IO.Path.GetFileName.

  • Si tiene que aceptar rutas de archivo como entrada, utilice la ruta completa del archivo mediante System.IO.Path.GetFullPath.

Uso de MapPath para evitar la asignación entre aplicaciones

Si utiliza MapPath para asignar una ruta virtual proporcionada a una ruta física en el servidor, utilice la sobrecarga de Request.MapPath, que acepta un parámetro bool, con el fin de poder evitar la asignación entre aplicaciones. En el siguiente ejemplo de código se muestra esta técnica.

try
{
  string mappedPath = Request.MapPath( inputPath.Text, 
                                       Request.ApplicationPath, false);
}
catch (HttpException)
{
  // Cross-application mapping attempted
}

El último parámetro false impide la asignación entre aplicaciones. Esto quiere decir que un usuario no puede proporcionar correctamente una ruta que contenga ".." para salir de la jerarquía de directorios virtuales de la aplicación. Siempre que se intente hacer, se generará una excepción del tipo HttpException.

Si utiliza controles del servidor, puede utilizar el método Control.MapPathSecure para recuperar la ruta física a la que está asignada la ruta virtual. Control.MapPathSecure utiliza seguridad de acceso al código y genera una excepción HttpException si el control del servidor no dispone de permisos para leer el archivo asignado resultante. Para obtener más información, consulte Control.MapPathSecure en la documentación de .NET Framework SDK.

Uso de la seguridad de acceso al código para restringir E/S de archivo

Un administrador puede restringir la E/S de archivo a su propia jerarquía de directorios virtuales si configura la aplicación para que se ejecute con un nivel de confianza medio. En este caso, la seguridad de acceso al código .NET impide que se tenga acceso a archivos fuera de la jerarquía de directorios virtuales de la aplicación.

Para configurar la aplicación a fin de que se ejecute con el nivel de confianza medio, establezca el elemento <trust> en Web.config o Machine.config.

<trust level="Medium" />

Validación de URL

Puede filtrar por un formato URL válido si utiliza una expresión regular como la que se muestra a continuación.

^(?:http|https|ftp)://[a-zA-Z0-9\.\-]+(?:\:\d{1,5})?(?:[A-Za-z0-
9\.\;\:\@\&\=\+\$\,\?/]|%u[0-9A-Fa-f]{4}|%[0-9A-Fa-f]{2})*$

De este modo se restringe la entrada, pero no se valida si la URL es válida en términos de límites de la aplicación. Debería comprobar si el destino es válido en el contexto de la aplicación. Por ejemplo, compruebe si apunta a un servidor autorizado con el que espera que se comunique la aplicación.

Paso 3. Codificación de resultados no seguros

Si escribe texto de salida en una página Web, codifíquelo con HttpUtility.HtmlEncode. Hágalo si el texto procedía de entradas del usuario, una base de datos o un archivo local.

Del mismo modo, si escribe URL que puedan contener caracteres no seguros porque se han construido a partir de datos de entrada o de datos de una base de datos compartida, utilice HttpUtilty.UrlEncode para hacer que sean seguras.

La codificación de los datos con anticipación es un error que hay que evitar. Asegúrese de que lleva a cabo la codificación justo antes de se muestren los datos al cliente.

Uso de HtmlEncode para codificar resultados no seguros

El método HtmlEncode reemplaza caracteres que tengan un significado especial en HTML por variables HTML que representen a esos caracteres. Por ejemplo, se reemplaza < por < y " por ". Los datos codificados no hacen que el explorador ejecute código. En lugar de eso, los datos se procesan como texto inofensivo y las etiquetas no se interpretan como HTML.

Para ilustrar el uso de HtmlEncode, la siguiente página acepta entradas del usuario y permite caracteres HTML potencialmente no seguros al establecer el valor ValidateRequest="false". Antes de devolver la entrada al usuario, el código llama a HttpUtility.HtmlEncode en el texto de entrada proporcionado. De este modo, el HTML potencialmente no seguro se procesa como texto inofensivo.

<%@ Page Language="C#" ValidateRequest="false" %>

<script runat="server">
  void submitBtn_Click(object sender, EventArgs e)
  {
      Response.Write(HttpUtility.HtmlEncode(inputTxt.Text));
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
  <body>
    <form id="form1" runat="server">
      <div>
        <asp:TextBox ID="inputTxt" Runat="server" 
             TextMode="MultiLine" Width="382px" Height="152px">
        </asp:TextBox>
        <asp:Button ID="submitBtn" Runat="server" Text="Submit" 
                    OnClick="submitBtn_Click" />
      </div>
    </form>
  </body>
</html>

Para ver los efectos de la codificación HTML, coloque la página anterior en un directorio virtual, desplácese hasta ella, introduzca código HTML en el cuadro de texto de entrada y haga clic en Enviar. Por ejemplo, la siguiente entrada se procesa como texto.

Run script and say hello <script>alert('hello');</script>

Produce el siguiente resultado seguro.

Run script and say hello <script>alert('hello');</script>

Si quita la llamada a HtmlEncode y vuelve a escribir la entrada, el explorador ejecutará la secuencia de comandos y mostrará un cuadro de mensaje. Las secuencias de comandos malintencionadas pueden suponer una seria amenaza.

Uso de UrlEncode para codificar URL no seguras

Si necesita escribir URL basadas en entradas de las que no se fía plenamente, utilice HttpUtility.UrlEncode para codificar la cadena de URL.

HttpUtility.UrlEncode( urlString );

Paso 4. Uso de parámetros de comandos para consultas SQL

Para ayudar a evitar inyecciones SQL, utilice parámetros de comandos con las consultas SQL. La colección Parameters ofrece comprobaciones de tipo y validación de longitud. Si utiliza la colección Parameters, los datos de entrada se tratan como valores literales y SQL no los considera código ejecutable. Otra ventaja del uso de la colección Parameters es que se pueden realizar comprobaciones de tipo y de longitud. Los valores no comprendidos en el intervalo generan una excepción.

Uso de la colección Parameters al llamar a procedimientos almacenados

En el siguiente fragmento de código se muestra cómo utilizar la colección Parameters cuando se llama a un procedimiento almacenado.

SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", 
                                     myConnection);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parm = myCommand.SelectCommand.Parameters.Add(
                                       "@LoginId", SqlDbType.VarChar, 11);
parm.Value = Login.Text;

Uso de la colección Parameters al crear instrucciones SQL

Si no puede utilizar procedimientos almacenados, puede utilizar parámetros, tal y como se muestra en el siguiente fragmento de código.

SqlDataAdapter myCommand = new SqlDataAdapter(
"SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", myConnection);
SQLParameter parm = myCommand.SelectCommand.Parameters.Add(
                           "@au_id" ,SqlDbType.VarChar, 11);
Parm.Value = Login.Text;

Para obtener más información sobre la prevención de inyecciones SQL, consulte Cómo: Proteger ASP.NET de inyecciones SQL.

Paso 5. Comprobación de que no se devuelven errores ASP.NET al cliente

Puede utilizar el elemento <customErrors> para configurar mensajes de error genéricos personalizados que deben devolverse al cliente si se diera una condición de excepción en la aplicación.

Asegúrese de que el atributo mode esté establecido como "remoteOnly" en el archivo web.config, tal y como se muestra en el siguiente ejemplo.

<customErrors mode="remoteOnly" />

Después de instalar una aplicación ASP.NET, puede cambiar la configuración para que apunte a la página de errores personalizada, tal y como se muestra en el siguiente ejemplo.

<customErrors mode="On" defaultRedirect="YourErrorPage.htm" />

Recursos adicionales

Para obtener más información sobre la protección de la aplicación frente a ataques de inyección, consulte los siguientes documentos:

Comentarios

Si desea enviar comentarios puede utilizar la wikipedia (en inglés) o el correo electrónico:

Nos interesan especialmente sus comentarios sobre los aspectos siguientes:

  • Problemas técnicos relacionados con nuestras recomendaciones

  • Problemas de aprovechamiento y utilidad

Soporte técnico

Los servicios de soporte de Microsoft ofrecen el soporte técnico de los productos y tecnologías de Microsoft a los que se hace referencia en esta guía. Para obtener información sobre soporte, visite el sitio Web de soporte de Microsoft en http://msdn.microsoft.com/security/default.aspx?pull=/isapi/gosupport.asp?Target=/.

Comunidad y grupos de noticias

El soporte técnico de la comunidad se ofrece en los foros y grupos de noticias:

Para sacar el mayor partido de estos foros, busque el grupo de noticias correspondiente a su tecnología o problema. Por ejemplo, si tiene un problema con las características de seguridad de ASP.NET, debería utilizar el foro de seguridad de ASP.NET (ASP.NET Security).

Colaboradores y revisores

  • Colaboradores y revisores externos: Andy Eunson; Chris Ullman, Content Master; David Raphael, Foundstone Professional Services, Rudolph Araujo, Foundstone Professional Services; Manoranjan M. Paul

  • Colaboradores y revisores de PSS y Microsoft Consulting Services: Wade Mascia, Tom Christian, Adam Semel, Nobuyuki Akama, Microsoft Corporation

  • Colaboradores y revisores de Microsoft Product Group: Stefan Schackow, Vikas Malhotra, Microsoft Corporation

  • Colaboradores y revisores de MSDN: Kent Sharkey, Microsoft Corporation

  • Colaboradores y revisores de Microsoft IT: Eric Rachner, Shawn Veney (ACE Team), Microsoft Corporation

  • Equipo de pruebas: Larry Brader, Microsoft Corporation; Nadupalli Venkata Surya Sateesh, Sivanthapatham Shanmugasundaram, Sameer Tarey, Infosys Technologies Ltd.

  • Equipo de edición: Nelly Delgado, Microsoft Corporation; Sharon Smith, Tina Burden McGrayne, Linda Werner & Associates Inc.

  • Dirección de publicación: Sanjeev Garg, Satyam Computer Services

Mostrar: