Redirect to a page with endResponse to true VS CompleteRequest and security thread
Solution 1
You must call the redirect always with endRespose=true
or else any hacker can see whats on the page by simple hold the redirect.
To prove that I use the NoRedirect plugin for Firefox to hold the redirect. Then I test the two cases and here is the results:
I have a simple page with that text inside it
<form id="form1" runat="server">
<div>
I am making a redirect - you must NOT see this text.
</div>
</form>
and then on Page load try to make the redirect with both cases:
First case, using the Complete Request();
try
{
// redirect with false that did not throw exception
Response.Redirect("SecondEndPage.aspx", false);
// complete the Request
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
catch (Exception x)
{
}
and there boom, you can see whats inside the page !
And second case
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)
{
}
Nothing shown now.
So if you do not like a hacker to see whats on your page, you must call it with endResponse to true and stop what other processing is made -eg return from function and not continue.
If for example you check if the user is authenticated he can see that page or if not he must redirect to login, and even in the login if you try to redirect him with endResponse to false, then holding the redirect the hacker can see - what you believe that can not because you use the Redirect.
My basic point here is to show the security thread that exist if you are not stop to send data back to the browser. The redirect is a header and instruction to the browser, but at the same time you need to stop send any other data, you must stop send any other part of your page.
Solution 2
It is not required to call Response.Redirect
with true
for endResponse
to solve the security issue of outputting the page content after the redirect call. You can accomplish this another way and avoid causing a ThreadAbortException at the same time (which is always bad). Below are snippets of a page I created with 5 buttons that cause redirects in different ways, the RedirectRenderOverride
button being the ideal as it is the one that triggers the Render method to do nothing. This has been tested with the NoRedirect add-in. Only two cases avoid outputting anything other than the 302 object moved response - RedirectEnd
and RedirectRenderOverride
.
Code In Front
<asp:Button ID="Button1" runat="server" OnClick="RedirectCompleteRequest" Text="RedirectCompleteRequest"/>
<asp:Button ID="Button2" runat="server" OnClick="RedirectClear" Text="RedirectClear"/>
<asp:Button ID="Button3" runat="server" OnClick="RedirectRenderOverride" Text="RedirectRenderOverride"/>
<asp:Button ID="Button4" runat="server" OnClick="RedirectEnd" Text="RedirectEnd"/>
<asp:Button ID="Button5" runat="server" OnClick="RedirectEndInTryCatch" Text="RedirectEndInTryCatch"/>
Code Behind
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
calls Thread.CurrentThread.Abort
internally and, according to Eric Lippert, calling Thread.Abort
, "is at best indicative of bad design, possibly unreliable, and extremely dangerous."
Aristos
Electrical Engineering degree and PhD in Software Engineering. I started programming at the age of 13 using the now old, ZX Spectrum on my TV. When I was younger, I used to make PCB electronic circuits. I mostly work with c++/c#, assembly, asp.net, SQL, javascript including ajax and jQuery, but i also write on many others, including Lingo of Director, and Prolog. Also one of the first creators of my university site back in 1996, among other sites. The last 13+ years I work on an asp.net projects, and so my focus here on SO is on that topic. I like the community here, and I even love to help and get help. Ah, and when I'm bored I make watches: Work full time for a multinational company, making inside private software tools. You can also check this site: http://www.athineon.com/
Updated on June 14, 2022Comments
-
Aristos almost 2 years
Base on this questions and the answers there, I like to ask what is the proper way of redirecting.
The default way using the Redirect(url, endResponse) is throw the
ThreadAbortException
because is called withendResponse=true
that calls theEnd()
method and so, if you use it inside a try/catch block, this exception shown there and that can be assumed as error, but actually a user is try to redirect to a page by stopping the rest of the page processing.The other possible ways is to call the
Redirect(url, endResponse)
withendResponse=false
following byHttpContext.Current.ApplicationInstance.CompleteRequest();
By using that you do not get any exceptions.So the question is what is better to use and why.
-
Aristos over 11 yearsThis is a totally different approach, compare it with your answer here stackoverflow.com/a/14640542/159270 where you do not explain the issue and the security thread !
-
Sumo over 11 yearsI do mention the approach and provide a link stating, "To avoid postback handling and HTML rendering, you need to do more: web.archive.org/web/20101224113858/http://www.c6software.com/…"
-
Aristos over 11 yearsI read the article and the only argument I see is: is not good to throw exceptions. You say- you need to do more, and give a link that have other links...
-
Aristos over 11 yearsyou have fun :) you place a Respnse.Write inside the
finally
hehehe, the finally is used to clear some object, not to write on page. :) Ok you have fun. -
Sumo over 11 yearsDidn't say it was good code. It proves a point that the ThreadAbortException and the thread is really not dead yet, nor may never be. You make a valid security point which folks need to think about. But, if Microsoft is documenting the fact that you should never call it, another approach must be found.
-
Aristos over 11 yearsThe
Response.Write("Still doing stuff!");
is always render direct on the page, the Render function of yours did not stop it. I just test it. So when you won to stop something you responsible to stop and the rest of the render actions. Now the finally must run to clear/close some object, that is the reason to use it. -
Sumo over 11 yearsThat's correct, because the
_isTerminating
is false. The overrides in that code example are only being used when_isTerminating
is set to true, which only happens in theRedirectRenderOverride
event handler. -
Aristos over 11 yearsyou do not understand, the
Response.Write
is send direct to the browser, is not pass from the render. Is not be used on code behind or you break the page. -
Sumo over 11 yearsAgain, correct. However, there are 5 distinct examples in this code example. They are not to be mixed together. The Response.Write in that part of the example of something that can happen where you think you've aborted the thread to do the redirect. It's not part of the Render override example.
-
Aristos over 11 yearsThis code is a nice idea, to stop the rendering - but I say you again, you do not point that out on your answers when you say to the users to avoid to use the endRequest with true - and you place them in a security thread just because they do not understand what is this exception and thy afraid of it.
-
Aristos over 6 yearsif you negative vote, please consider to say what is the issue with this approach.
-
Dai over 4 yearsDownvoted (not least because "hacker" is inappropriate terminology) but because Microsoft themselves say to not use
endResponse: true
orResponse.Redirect(String)
. Code that throwsThreadAbortException
is bad anyway for many reasons I won't get into. The solution is simple: useResponse.SuppressContent = true
(and ideally, don't render anything instead of suppressing rendered content to save wasted CPU time). -
Aristos over 4 years@Dai Thank you for the comments - I will find some times to make some tests with the
SuppressContent
(and I will update the answer). About theis bad anyway for many reasons I won't get into
, if you have some article to read about, or give me one of that many reasons to consider them. Thank you again for your replay. -
Dai over 4 years