Redirigir a una página con endResponse a verdadero VS CompleteRequest y hilo de seguridad

Basándome en estas preguntas y las respuestas allí , me gustaría preguntar cuál es la forma correcta de redirigir.

La forma predeterminada de utilizar el redireccionamiento (url, endResponse) es lanzar ThreadAbortException porque se llama con endResponse=true que llama al método End() y, por lo tanto, si lo usa dentro de un bloque try / catch, esta excepción se muestra allí y eso puede se asume como un error, pero en realidad un usuario intenta redirigir a una página deteniendo el rest del procesamiento de la página.

Las otras formas posibles son llamar a Redirect(url, endResponse) con endResponse=false following by HttpContext.Current.ApplicationInstance.CompleteRequest(); Al usar eso no obtienes ninguna excepción.

Entonces, la pregunta es qué es mejor usar y por qué.

Debe llamar a la redirección siempre con endRespose=true o de lo contrario cualquier hacker puede ver lo que está en la página simplemente mantenga presionada la redirección.

Para demostrar que utilizo el complemento NoRedirect para Firefox para mantener el redireccionamiento. Luego pruebo los dos casos y aquí están los resultados:

Tengo una página simple con ese texto dentro

 
I am making a redirect - you must NOT see this text.

y luego en la carga de página intente hacer la redirección con ambos casos:

Primer caso, utilizando la Solicitud completa ();

  try { // redirect with false that did not throw exception Response.Redirect("SecondEndPage.aspx", false); // complete the Request HttpContext.Current.ApplicationInstance.CompleteRequest(); } catch (Exception x) { } 

y allí boom, ¡puedes ver lo que está dentro de la página!

Y segundo caso

 try { // this is throw the ThreadAbortException exception Response.Redirect("SecondEndPage.aspx", true); } catch (ThreadAbortException) { // ignore it because we know that come from the redirect } catch (Exception x) { } 

Nada se muestra ahora.

Entonces, si no le gusta que un hacker vea lo que está en su página, debe llamarlo con endResponse a true y detener lo que se hace con otro procesamiento, por ejemplo, devolver de la función y no continuar.

Si, por ejemplo, comprueba si el usuario está autenticado, puede ver esa página o, si no, debe redireccionar para iniciar sesión, e incluso en el inicio de sesión si intenta redirigirlo con endResponse a falso, entonces, manteniendo el redireccionamiento, el pirata puede ver qué usted cree que no puede porque usa el redireccionamiento.

Mi punto básico aquí es mostrar el hilo de seguridad que existe si no se detiene a enviar datos de vuelta al navegador. El redireccionamiento es un encabezado e instrucciones para el navegador, pero al mismo tiempo debe dejar de enviar cualquier otra información, debe dejar de enviar cualquier otra parte de su página.

No es necesario llamar a Response.Redirect con true para endResponse para resolver el problema de seguridad de generar el contenido de la página después de la llamada de redirección. Puede lograr esto de otra manera y evitar causar una ThreadAbortException al mismo tiempo (lo cual siempre es malo ). A continuación se muestran fragmentos de una página que creé con 5 botones que causan redirecciones de diferentes maneras, siendo el botón RedirectRenderOverride el ideal, ya que es el que desencadena el método Render para no hacer nada. Esto ha sido probado con el complemento NoRedirect. Solo dos casos evitan dar salida a otra cosa que no sea la respuesta movida del objeto 302: RedirectEnd y RedirectRenderOverride RedirectEnd RedirectRenderOverride .

Código en frente

      

Código detrás

 public partial class _Default : Page { private bool _isTerminating; protected void RedirectEnd(object sender, EventArgs e) { Response.Redirect("Redirected.aspx"); } protected void RedirectCompleteRequest(object sender, EventArgs e) { Response.Redirect("Redirected.aspx", false); HttpContext.Current.ApplicationInstance.CompleteRequest(); } protected void RedirectClear(object sender, EventArgs e) { Response.Clear(); Response.Redirect("Redirected.aspx", false); } protected void RedirectRenderOverride(object sender, EventArgs e) { Response.Redirect("Redirected.aspx", false); _isTerminating = true; } protected void RedirectEndInTryCatch(object sender, EventArgs e) { try { Response.Redirect("Redirected.aspx"); } catch (ThreadAbortException) { // eat it } finally { Response.Write("Still doing stuff!"); } } protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument) { if (!_isTerminating) { base.RaisePostBackEvent(sourceControl, eventArgument); } } protected override void Render(HtmlTextWriter writer) { if (!_isTerminating) { base.Render(writer); } } } 

Response.End llama a Thread.CurrentThread.Abort internamente y, según Eric Lippert , llamando a Thread.Abort , “es en el mejor de los casos un mal diseño, posiblemente poco confiable y extremadamente peligroso”.