Validación de peticiones en ASP.NET, o cómo evitar el error “Request.Form peligroso”

La validación de peticiones es un mecanismo integrado en ASP.NET que evita la entrada al sistema de valores considerados “peligrosos” para su integridad, como tags y otros elementos utilizables para la inyección de scripts (XSS) o introducción de valores no controlados.

Dado que está implementado a nivel de plataforma ASP.NET, los valores recibidos en parámetros de entrada son vigilados con ASP.NET MVC,  WebForms e incluso WebPages (la tecnología incluida en el nuevo WebMatrix).

Así, en cada petición son analizados los valores recibidos en el query string, cookies y campos de formulario, generándose una bonita pantalla de error cuando se identifica algo sospechoso:

Error de validación

Según el comportamiento por defecto, el framework realiza esta comprobación en el método IsDangerousString() de una clase interna de System.Web, llamada CrossSiteScriptingValidation. Si estudiamos su implementación, podemos observar que se comprueban los siguientes aspectos:

  • si se detecta algún ampersand “&”, se asegura que el siguiente carácter no sea una almohadilla “#”. Esto impide la entrada de entidades como “|”
  • si se detecta algún símbolo “<”, se asegura que el siguiente carácter no sea alfabético, el signo de exclamación “!”, interrogación “?” o la barra de división “/”. Esto evitará la entrada de etiquetas HTML (como <script>), el cierre de las mismas o la introducción de directivas o comentarios, aunque dejará pasar algunas expresiones que pueden ser construcciones lógicas como “a<1”.

Al violarse alguna de las reglas anteriores es cuando el sistema lanza la excepción HttpRequestValidationException, cuya representación en pantalla hemos visto anteriormente.

Aunque en la mayoría de ocasiones este mecanismo es muy útil, hay escenarios en los que se vuelve en nuestra contra. Por ejemplo, si en el formulario de datos hay campos destinados a la introducción de texto enriquecido, no nos permitirá la recepción de estos valores, pues normalmente incluirán tags HTML.

Veamos cómo podemos desactivar la comprobación de valores de entrada en distintos casos.

Desactivación en versiones anteriores a ASP.NET 4

Antes de la llegada de ASP.NET 4, en Webforms era posible desactivar la validación de peticiones simplemente añadiendo la directiva ValidateRequest=false en las páginas:

ValidateRequest en páginas
Para evitar la introducción de esta directiva en todas las páginas, podíamos hacerlo de forma global en el web.config, añadiendo el atributo validateRequest="false" en la sección <pages> del system.web:

ValidateRequest en web.config
También en ASP.NET MVC era posible desactivar este comportamiento muy fácilmente añadiendo a la acción del control destinataria de los datos del formulario el atributo [ValidateInput] enviándole false como argumento:

Atributo ValidateInput

Desactivación en ASP.NET 4

ASP.NET 4 ha introducido una serie de breaking changes que pueden hacer que aplicaciones web que antes funcionaban correctamente dejen de hacerlo. Uno de estos cambios es la forma en que se validan las peticiones.

Concretamente, se ha modificado el momento en el ciclo de vida del tratamiento de las peticiones donde se realiza la validación de la información de entrada. De esta forma, ahora se aplicarán también a servicios web, handlers o módulos HTTP personalizados, que antes no eran comprobados.

Así, por defecto, se realizará la validación antes de que entren en escena las directivas de página en Webforms o los atributos del controlador, por lo que se producirá la excepción de validación aunque la hayamos desactivado con ellos.

La forma de evitar esto es indicar en el web.config que queremos trabajar en modo compatible con versiones anteriores, introduciendo en el elemento <httpRuntime> el atributo requestValidationMode="2.0":

requestValidationMode

¿Y la desactivación para un único campo?

En apartados anteriores hemos visto cómo desactivar las comprobaciones de la petición sobre páginas (en el caso de Webforms) y acciones (en ASP.NET MVC). El problema de la aparición del error “se detectó un posible valor Request.Form peligroso” lo solucionaríamos muy rápidamente con las técnicas descritas.

Sin embargo, fijaos que al deshabilitar la validación lo hacemos sobre la petición completa; por ejemplo, si la desactivamos para una página donde existe un único campo en el que debe introducirse HTML estaríamos abriendo la posibilidad de que un usuario malintencionado introdujera código script en otros campos del formulario a los que posiblemente no prestemos tanta atención.

Curiosamente, analizando el código de ASP.NET he descubierto que existe un atajo que nos permite saltarnos la validación en un campo concreto del formulario, aunque la comprobación de peticiones se encuentre habilitada para la página, como es por defecto.

El hecho es que si el nombre del campo del formulario comienza por dos caracteres de subrayado, por ejemplo, “__Texto”, no se efectúan sobre él las comprobaciones de validación, probablemente para evitar que se realice sobre los campos especiales como “__VIEWSTATE ” o “__EVENTVALIDATION”.

Por tanto, si introducimos en un formulario cuadros de texto o textareas en los que queremos saltarnos esta validación, basta con nombrarlos siguiendo esta regla, como en el siguiente ejemplo, para ASP.NET MVC:

Uso en ASP.NET MVC
Asimismo, puede utilizarse con ASP.NET Webforms. En este caso, sólo debemos asegurarnos de que el nombre (el atributo name) asignado en cliente al control comience por el doble subrayado:

Uso en WebformsPublicado en: Variable not found.

4 comentarios en “Validación de peticiones en ASP.NET, o cómo evitar el error “Request.Form peligroso””

  1. Buenas! Muy buen artículo.

    Sólo comentar, para “completitud” que para deshabilitar la validación EN UN SOLO campo en MVC3 podemos usar [ValidateInput(true, Exclude=”parametro”)] validar todos los parámetros excepto el indicado:

    [HttpPost]
    [ValidateInput(true, Exclue=”texto”)]
    public ActionResult Edit(int id, string texto) {
    }

    Con eso no es necesariok hacer el “truco” de que empieze por __ (que es un poco guarro :P).

    Y también si queremos especificar esto, no a nivel de acción, sinó a nivel de propiedad de ViewModel podemos hacerlo con [AllowHtml] (a partir de MVC3 RC2, antes se llamaba [SkipRequestValidation]).
    Algo así como:

    class MyData
    {
    public int id { get; set;}
    [AllowHtml]
    public string texto { get; set;}
    }

    Y en el controlador:
    [HttpPost]
    public ActionResult Edit(MyData data)
    {
    }

    Un saludo!

  2. Buenas!

    Jejeje, pues sí, Eduard! En MVC 3 tenemos esta posibilidad, y supongo que en breve se extenderá de alguna u otra forma a webforms y webpages.

    El siguiente post en VNF trataba sobre eso… 😉

    Saludos.

  3. Otra forma sería capturar el evento Application_Error en el global.asax y verificar si se trata de una HttpRequestValidationException

    protected void Application_Error(object sender, EventArgs e)
    {
    Exception ex = Server.GetLastError();
    if (ex is HttpRequestValidationException)
    {
    GuardarLogs(Request.UserHostAddress);
    Server.Transfer(“ErrorRequest.aspx”);
    }
    }

    Por cierto, excelente página, estoy comenzando con ASP.NET MVC y es como una mina de oro :D. Gracias. Saludos y ¡Feliz Navidad!.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *