Seguridad en ASP.NET (XSS)

Al empezar a escribir, iba a comentar un "bug" presente en ASP.NET 2.0, pero para no hacer tan larga -y aburrida- esta entrada, lo haré en dos partes

ASP.NET, provee por defecto una limitada protección contra ataques XSS a través del atributo ValidateRequest, que se puede definir tanto a nivel de página como a nivel de la aplicación.

Esta validación se asegura por ejemplo que detrás del caracter <, no exista ninguna letra, caso contrario recibirían una excepción del tipo HttpRequestValidationException, con el siguiente mensaje (se usa <a como ejemplo):

A potentially dangerous Request.QueryString value was detected from the client (ReturnUrl="<a").

Description: Request Validation has detected a potentially dangerous client input value, and processing of the request has been aborted. This value may indicate an attempt to compromise the security of your application, such as a cross-site scripting attack. You can disable request validation by setting validateRequest=false in the Page directive or in the configuration section. However, it is strongly recommended that your application explicitly check all inputs in this case.

Exception Details: System.Web.HttpRequestValidationException: A potentially dangerous Request.QueryString value was detected from the client (ReturnUrl="<a").

El código donde se hace esta validación está ubicado en el método ValidateString de la clase HttpRequest, que a su vez hace uso del método IsDangerousString de la clase CrossSiteScriptingValidation.

Al utilizar Reflector para ver el código del último método mencionado, se tiene lo siguiente (los comentarios los puse yo :) ):

csharp:
internal static bool IsDangerousString(string s, out int matchIndex)
{
      matchIndex = 0;
      int num1 = 0;
      while (true)
      {
            // La cadena contiene uno de estos caracteres: <, &
            int num2 = s.IndexOfAny(CrossSiteScriptingValidation.startingChars, num1);
            if (num2 < 0)
            {
                  return false;
            }
            if (num2 == (s.Length - 1))
            {
                  return false;
            }
            matchIndex = num2;
            char ch1 = s[num2];
            if (ch1 != '&')
            {
                  // Valida que la cadena no contenga <! o <[a-z]
                  if ((ch1 == '<') && (CrossSiteScriptingValidation.IsAtoZ(s[num2 + 1]) || (s[num2 + 1] == '!')))
                  {
                        return true;
                  }
            }
            else if (s[num2 + 1] == '#')
            {
                  return true;
            }
            num1 = num2 + 1;
      }
}

Como vieron, esta validación que se hace es muy sencilla y definitivamente no deberíamos confiar en esta característica para decir que nuestra aplicación no es vulnerable a cierto tipo de ataques. En la siguiente entrada comentaré el "bug" de ASP.NET 2 :)