Introduction
Trace is a great diagnosing feature in ASP.NET and it is a very useful tool to debug the ASP.NET applications especially in production servers where we are not able to debug the applications. Trace collects the diagnosing information like page execution flow, request information, custom trace messages and other diagnosing information at runtime to debug an application. Basically, it appends the collected information into a page or trace viewer (Trace.axd) content. The flip side, the trace introduces a high vulnerability security risk by exposing all essential information of an application to the outside world, so hackers can use this information and play around it. This is one of the reasons why we have been advised to stop trace on production servers (also it has performance impact).
Trace.axd is a virtual and hardcoded resource to access the trace viewer and it is well known for information leak in the application security world. Hackers can use this trace.axd to collect the information when trace is enabled on a web application. Another problem is we can’t rename the Trace.axd to custom name and there is no straight forward option that exists in ASP.NET. I found some interesting steps to rename the Trace.axd and in this article, we are going to see how to rename the Trace.axd to custom resource name in ASP.NET step by step.
Pre-requisites
I am assuming that you have knowledge on ASP.NET trace, HTTP handler and module concepts. Having knowledge on response filter is nice to have but it is not mandatory. If you don’t have knowledge about the above mentioned items, don't worry just go through the following links then come back here for better understanding.
Background
In ASP.NET, all requests related to dynamic resources are handled by corresponding http handlers, same way the trace viewer request (Trace.axd) is handled by TraceHandler
from System.Web
namespace. With this information, we can add a handler configuration to web.config with an alternate name for Trace.axd. But the problem is not solved completely because the trace handler injects the Trace.axd references into hyperlinks so when user clicks on these hyperlinks, it will navigate to Trace.axd. As you know, we can’t modify the trace handler content directly so we can't replace Trace.axd references from the trace viewer output until and unless we are creating our own trace handler but fortunately we have an option in ASP.NET called Response Filter which can alter the response before sending to the browser. Response filter is a specialized version of stream and it has options to read and write the response content.
Renaming of Trace.axd
By using http handler/module and response filter concepts, we are going to emulate the renaming of Trace.axd and it requires the following five steps:
- Enable the Trace
- Block the access of Trace.axd
- Configure an alternate name for Trace.axd
- Create a Response Filter
- Register the Response Filter
Enable the Trace
I am assuming that you have already enabled the trace option in web.config. Since it is prerequisites for other steps, I want to make sure that you have already done it. If not, please add the following configuration in web.config.
<system.web>
<trace enabled="true" localOnly="false"
pageOutput="false" requestLimit="500"
mostRecent="true" traceMode="SortByTime"/>
</system.web>
Alter the above settings according to your needs.
Block the Access of Trace.axd
As long as trace is enabled, we can access the Trace.axd from outside the world so we need to block the access of Trace.axd just like how the web.config is blocked in web server. We can do the same for Trace.axd by simply adding the following configuration in web.config.
<system.webserver>
<security>
<requestfiltering>
<hiddensegments>
<add segment="Trace.axd"></add>
</hiddensegments>
</requestfiltering>
</security>
</system.webserver>
The above settings will not work with ASP.NET Development Server, so we need to deploy our solution on IIS7 or above to test the same.
When we are trying to access the Trace.axd from the local IIS server, it will return the following error message after adding the above configuration in web.config.
When we are trying to access the Trace.axd from remote machine, it will return the following message:
Configure an Alternate Name for Trace.axd
Next step, we need to specify the custom name to access the trace viewer, to do that, add the following configuration in web.config. Here, I given Eventviewer.aspx as an alternate resource to Trace.axd and you can give whatever name you want.
<system.web>
<httpHandlers>
<add verb="GET,POST" path="Eventviewer.aspx"
validate="false" type="System.Web.Handlers.TraceHandler,
System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</httpHandlers>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers>
<add name="SmartTraceHandler" path="Eventviewer.aspx"
verb="GET,POST" type="System.Web.Handlers.TraceHandler, System.Web,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</handlers>
</system.webServer>
Now, you can access the trace viewer through eventviewer.aspx but as we know, the content of eventviewer
page still refers to Trace.axd in the hyperlinks. In the next section, we are going to see how to fix it.
Create a Reponse Filter
Fortunately, we have response filter in ASP.NET to alter the response before sending to the browser and we are going to use this response filter to replace Trace.axd with custom resource name in all hyperlinks. Response filter is a specialized form of stream
class and it overrides few important methods and properties of stream
class to read and write the response content. Here, I created a response filter called TraceFilter
and it has an overridden Write
method to find and replace all Trace.axd references. The following snippet shows the Write
method of TraceFilter
.
public override void Write(byte[] buffer, int offset, int count)
{
var content = _encoding.GetString(buffer, offset, count);
var checkTrace = new Regex("Trace.axd", RegexOptions.IgnoreCase);
if (checkTrace.IsMatch(content)) {
content = checkTrace.Replace(content, TraceFile);
buffer = _encoding.GetBytes(content);
}
_stream.Write(buffer, 0, buffer.Length);
}
Register the Response Filter
Now, we need to attach the new response filter in to response context but there is no easy way to do it (not like adding an http handler/http module configuration in web.config). In order to do it, we need to create an http module and attach it to the corresponding response context. Here, I created an http module called SmartTraceModule
and it will check for custom resource related request and attach our response filter to the response.
public class SmartTraceModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.ReleaseRequestState += new EventHandler(InstallTraceFilter);
}
private static void InstallTraceFilter(object sender, EventArgs e)
{
var context = HttpContext.Current;
var response = context.Response;
if (context.Request.RawUrl.ToLower().EndsWith(TraceFilter.TraceFile)
&& response.ContentType == "text/html")
response.Filter = new TraceFilter(response.Filter,response.ContentEncoding);
}
public void Dispose() {
}
}
Finally, we need to configure the SmartTraceModule
into web.config as below:
<system.web>
<httpModules>
<add name="SmartTraceModule" type="SmartTrace.SmartTraceModule, SmartTrace"/>
</httpModules>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<add name="SmartTraceModule" type="SmartTrace.SmartTraceModule, SmartTrace"/>
</modules>
</system.webServer>
Now, we are ready to access the trace viewer with custom name (in this case eventviewer.aspx). To test with attached sample project, do the following steps:
- Download the attached source and open the solution with Visual Studio 2010 or above version.
- Build and run the application. It will open the http://localhost:53927/ URL on your default browser and you will get the following screen:
- Click all buttons which displayed on the screen to produce some trace data. Then type URL http://localhost:53927/eventviewer.aspx to view the trace viewer and you will get the following trace viewer screen.
Here, we got the trace viewer successfully with new name (eventviewer.aspx) instead of Trace.axd. Since we did not change any functionality of trace viewer, it will work as it is how it works before. Here, you can click the view details link to navigate details view.
As we expected, the new resource name (eventviewer.aspx) is added to details page URL by our response filter.
Conclusion
In this article, we have seen how to rename the Trace.axd into custom resource name but this is not a bullet proof solution for security issues, in fact it introduces a little performance impact by modifying the response content (an additional step required to rename the Trace.axd from the response content). Leaving the trace viewer to public access is high vulnerability risk so restrict it to authorized persons with proper authentication. It is always better to stop the trace in production servers (for both performance and security improvements) but you can make use of this option in unavoidable situations. Thanks for reading this article and I hope it shared some useful information to you. Please provide your valuable feedback on this article.