En una entrada anterior había prometido comentar un pequeño bug presente en asp.net 2 -y probablemente versiones anteriores.
El escenario de este problema es el siguiente, un hábil desarrollador hace una pequeña página que se encarga de redireccionar a una URL que pasa como parámetro, ejemplo:
<script runat="server">
void Page_Load()
{
Response.Redirect(Request.Params["uri"]);
}
</script>
Bien, si nos ponemos a analizar el código generado con Reflector, podremos sacar unas cuantas conclusiones:
public void Redirect(string url, bool endResponse)
{
if (url == null)
{
throw new ArgumentNullException("url");
}
if (url.IndexOf('\n') >= 0) // no se permiten saltos de línea
{
throw new ArgumentException(HttpRuntime.FormatResourceString("Cannot_redirect_to_newline"));
}
if (this._headersWritten)
{
throw new HttpException(HttpRuntime.FormatResourceString("Cannot_redirect_after_headers_sent"));
}
url = this.ApplyAppPathModifier(url); // determina la ruta correcta si es una URL relativa
url = this.ConvertToFullyQualifiedRedirectUrlIfRequired(url); // Usa la url absoluta si está definida en el web.config
url = this.UrlEncodeRedirect(url); // Codifica espacios y caracteres especiales (ascii > 128)
this.Clear();
Page page1 = this._context.Handler as Page;
if (((page1 != null) && page1.IsPostBack) && page1.SmartNavigation)
{
this.Write("<BODY><ASP_SMARTNAV_RDIR url=\"");
this.Write(url);
this.Write("\"></ASP_SMARTNAV_RDIR>");
this.Write("</BODY>");
}
else
{
this.StatusCode = 0x12e; // Código HTTP 302
this._redirectLocation = url; // Se envía la cabecera Location con este valor
this.Write("<html><head><title>Object moved</title></head><body>\r\n");
// HttpUtility.HtmlEncode codifica sólo algunos caracteres (<, >, &, etc)
X this.Write("<h2>Object moved to <a href='" + HttpUtility.HtmlEncode(url) + "'>here</a>.</h2>\r\n");
this.Write("</body></html>\r\n");
}
if (endResponse)
{
this.End();
}
}
En la línea X del código mostrado, se puede observar que el desarrollador, en mi opinión, cometió un error al usar HttpUtility.HtmlEncode en lugar de HttpUtility.UrlEncode, puesto que si usamos javascript:alert("XSS")
como valor para el parámetro uri
del primer bloque de código, veremos que en Firefox se mostrará un mensaje XSS al hacer click en el enlace "here".
He puesto una prueba de concepto (abrir con Firefox, no funciona en IE) en un servidor gratuito con soporte para ASP.NET 2.