9

I have been involved in two projects recently which have required the removal of all HTTP Headers which can identify the site as either an ASP.Net site or as a SharePoint site. This is normally as a result of Penetration Testing.

Normally I would use a combination of web.config changes to remove some headers and a custom HTTPModule to remove some of the SharePoint specific headers.

Before anyone gets on their high horse about whether or not stripping HTTP Headers is advisable, please bear in mind that we have two web app extensions, one of which is for our public facing site and it is only for this one these changes have been configured (search crawling and collaboration/site editing happen on other web application extensions) and also this is a client request to comply with the output of a penetration test so its not really open to architectural debate.

I have outlined the changes I normally make below and these have always worked fine for me. However recently I was directed to the following post which implies that when performing this action in a custom HTTPModule we should not use the PreSendRequestHeaders method, but rather we should choose an event earlier in the application lifecycle to avoid issues with the HTTPCache module:

http://blogs.msdn.com/b/asiatech/archive/2010/10/18/heap-corruption-in-httpcachemodule-while-you-try-to-remove-http-headers-in-your-custom-http-module.aspx

I have attempted to test the method described in the post above, but when testing with SharePoint 2013 and IIS8 I have noticed some issues. The headers are not reliably removed in this scenario unless the PreSendRequestHeaders event is used. I have tried with several events in the lifecycle.

So my question is simple what is the correct way for this HTTPModule to work such that the heap corruption discussed above (is this a common issue, I have never seen it myself?) is not a problem and to ensure that the headers are consistently removed in IIS8 with SharePoint 2013.

NOTE: Probably warrants a second question but there appears to be two new HTTP Headers in SharePoint 2013 for SPRequestDuration and SPIisLatency. Anyone know what these are for and whether a HTTPModule is the correct place to remove them. What will this break if anything?

Current Solution

Web.Config Changes

To remove the 'X-AspNet-Version' header

<httpRuntime enableVersionHeader="False" />

To remove the 'X-Powered-By' and 'MicrosoftSharePointTeamServices' headers

   <system.webServer>
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
        <remove name="MicrosoftSharePointTeamServices" />
      </customHeaders>
    </httpProtocol>

Custom HTTPModule

To remove the additional unwanted HTTP Headers, adding this as an event handler for the PreSendRequestHeaders event.

    private void RemoveHeaders(object sender, EventArgs e)
    {   
        try
        {
            this._app.Response.Headers.Remove("Server");
            this._app.Response.Headers.Remove("X-SharePointHealthScore");
            this._app.Response.Headers.Remove("SPRequestGuid"); 
        }
        catch (Exception ex)
        {
            Trace.TraceError(string.Format("Failed to remove HTTP Headers.  Error: {0}, Stack Trace: {1}", ex.Message, ex.StackTrace));
        }
    }
4

As mentioned in the blog post you references, it simply needs to happen after the response has been created (i.e. the page content) and before the UpdateRequestCache event. The blog post shows an idea example of using the PostRequestReleaseState event. This happens almost immediately after the response is generated.

public void Init(HttpApplication app)
{
    app.PostReleaseRequestState += new EventHandler(app_PostReleaseRequestState);

}
void app_PostReleaseRequestState(object sender, EventArgs e)
{
    HttpContext.Current.Response.Headers.Remove("Server");
    HttpContext.Current.Response.Headers.Remove("X-SharePointHealthScore");
    HttpContext.Current.Response.Headers.Remove("SPRequestGuid");
}
  • 1
    BTW, removing HTTP headers for a public-facing site is not a bad idea when you want to obscure to the end users what the underlying system is. This reduces the surface area for compromising the site a bit by making it slightly harder for a hacker to identify what they are hacking. It's easy to hide "SharePoint" but not ASP.NET. The ViewState and other page elements give it away. – John Chapman Jan 16 '14 at 15:03
  • Thanks John, but I have tried using the PostReleaseRequestState event and others and this does not seem to work reliably with SharePoint 2013 and IIS 8. I completely agree on the value of obscuring the technology used in some cases. – Charles Lee Jan 17 '14 at 7:15
  • Hmm, in what cases is it not working? – John Chapman Jan 17 '14 at 15:15
  • Also, you have multiple web.configs you need to register your module in. You would need to do it for each content web application folder in inetpub as well as in the 15 HIVE Layouts folder (for _layouts content). – John Chapman Jan 17 '14 at 15:17
  • Thanks again John but I would not advise on editing the web.config file in the 15 HIVE as this is not a supported action. In terms of what does not work it is simply when the module is used on Windows Server 2012 with IIS8 and SharePoint 2013. I am unsure if there is a change in IIS8 which has resulted in this. – Charles Lee Jan 17 '14 at 15:34
3

In IIS8 (which you are using, if you are using SharePoint 2013) it uses ASP.NET 4.5. The application events are different from 3.5 and are raised in the following order:

  1. BeginRequest
  2. AuthenticateRequest
  3. PostAuthenticateRequest
  4. AuthorizeRequest
  5. PostAuthorizeRequest
  6. ResolveRequestCache
  7. PostResolveRequestCache After the PostResolveRequestCache event and before the PostMapRequestHandler event, an event handler (which is a page that corresponds to the request URL) is created. When a server is running IIS 7.0 in Integrated mode and at least the .NET Framework version 3.0, the MapRequestHandler event is raised. When a server is running IIS 7.0 in Classic mode or an earlier version of IIS, this event cannot be handled.
  8. PostMapRequestHandler
  9. AcquireRequestState
  10. PostAcquireRequestState
  11. PreRequestHandlerExecute The event handler is executed.
  12. PostRequestHandlerExecute
  13. ReleaseRequestState
  14. PostReleaseRequestState After the PostReleaseRequestState event is raised, any existing response filters will filter the output.
  15. UpdateRequestCache
  16. PostUpdateRequestCache
  17. LogRequest. This event is supported in IIS 7.0 Integrated mode and at least the .NET Framework 3.0
  18. PostLogRequest This event is supported IIS 7.0 Integrated mode and at least the .NET Framework 3.0
  19. EndRequest

I suggest that you want to target the last event in the stack, which is "EndRequest". I suggest you follow this article: http://support.microsoft.com/kb/307996

In the Init method, place something like this:

app.EndRequest += new EventHandler(OnEndRequest);

Create the OnEndRequest method, which hooks up to the EndRequest event of HttpApplication:

HttpResponse response = HttpContext.Current.Response;
if (response != null)
{
    var responseHeaders = response.Headers;
    if (responseHeaders != null)
    {
        responseHeaders.Remove("X-AspNet-Version");
        responseHeaders.Remove("Server");
        responseHeaders.Remove("X-SharePointHealthScore");
        responseHeaders.Remove("SPRequestGuid");
        responseHeaders.Add("X-Some-Header-OrAnother", "some server name or another");
    }
}

IIS7 and IIS8 uses a different schema for the web.config, so add a section.

<configuration>
    <system.webServer>
        <modules>
            <add name="NameSpaceOfHttpModules" type="NameSpaceOfHttpModules.NameOfClass, NameSpaceOfHttpModules"/>
        </modules>
    </system.webServer>
</configuration>
  • Thanks George. I will try this when I have a chance +1 for now as it sounds positive. – Charles Lee Feb 12 '14 at 9:41
  • I've found that the EndRequest event of HttpApplication is TOO late in the stack, and it throws an error Error=Server cannot append header after HTTP headers have been sent., you need to use the 'PreSendRequestHeaders' – George Leithead Feb 21 '14 at 15:10
  • See link – George Leithead Feb 21 '14 at 15:39
  • Thanks George, but that leaves me back where I started with the heap corruption issue identified in the original question :-( – Charles Lee Feb 22 '14 at 21:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.