1

On my site, I want to disallow HTTP HEAD requests and have them answered with the 405 status code (Method not allowed). To achieve this I have the following in my web.config file:

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
    <remove name="TelemetryCorrelationHttpModule" />
    <add name="TelemetryCorrelationHttpModule" type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation" preCondition="integratedMode,managedHandler" />
    <remove name="ApplicationInsightsWebTracking" />
    <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
  </modules>
  <handlers>
    <clear />
    <add name="DenyHead" path="*" verb="HEAD" type="System.Web.HttpMethodNotAllowedHandler" />
    <add name="DebugAttachHandler" path="DebugAttach.aspx" verb="DEBUG" type="System.Web.HttpDebugHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    <add name="StaticFile" path="*" verb="*" modules="StaticFileModule" resourceType="Either" requireAccess="Read" />
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  </handlers>
  <security>
    <requestFiltering allowDoubleEscaping="true">
      <verbs allowUnlisted="false">
        <add verb="GET" allowed="true" />
        <add verb="POST" allowed="true" />
        <add verb="HEAD" allowed="true" />
        <add verb="DEBUG" allowed="true" />
      </verbs>
    </requestFiltering>
  </security>
</system.webServer>

Unfortunately, this doesn't work - I'm receiving bog-standard 404s instead.

Enabling failed request tracing yields the following:

20  HANDLER_CHANGED OldHandlerName
                    NewHandlerName DenyHead
                    NewHandlerType System.Web.HttpMethodNotAllowedHandler

...

61  AspNetPipelineEnter Data1 <Application_BeginRequest in my ASP.NET application>

...

135 HANDLER_CHANGED OldHandlerName System.Web.HttpMethodNotAllowedHandler
                    NewHandlerName System.Web.Mvc.MvcHandler

...

169 MODULE_SET_RESPONSE_ERROR_STATUS Notification EXECUTE_REQUEST_HANDLER
                                     HttpStatus   404

This seems to show that the DenyHead handler is somehow being replaced/overridden by my MVC application, but there's no code in my app that does anything of the sort.

I've tried alternative recommendations such as the answers here, but they give the same result.

  • Request filtering isn't an option because the status code it returns is not configurable (it always returns a 404).
  • Action filters aren't an option because they won't be hit for static content, and I don't want to send everything through the MVC pipeline.
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138

2 Answers2

0

You can create action filter, and check for request method. If it is "HEAD", you can reject request by settings Result property on filterContext and set statuscode to 405 method not allowed.

Or You can check above logic for Application_BeginRequest in Global.aspx and do the same.

Ameya
  • 726
  • 6
  • 9
  • I'd prefer to do this by configuration, if possible, and according to Microsoft it seems like that should be possible. – Ian Kemp May 23 '19 at 10:32
  • Do you have access to IIS manager? You can then restrict that in handler mapping https://stackoverflow.com/questions/12440277/how-do-i-enable-http-put-and-delete-for-asp-net-mvc-in-iis – Ameya May 23 '19 at 11:03
0

I wouldn't use IIS configuration as it gets you dependant on IIS, even though you might already be. Using a filter removes that dependency, just like that:

public class VerbFilter : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        if (context.HttpContext.Request.Method == "HEAD")
        {
            context.Result = new StatusCodeResult(405);
        }
        else
        {
            await next();
        }
    }
}
Yann Thibodeau
  • 1,111
  • 1
  • 12
  • 20