10

We have an ASP.Net MVC3 site only accessible over HTTPS, by using the RequireHTTPS attribute on the controller.

We are receiving numerous HTTP HEAD method requests, mainly from what appear to be Twitter bots. The default ASP.Net/MVC3 response is a '500 Internal Server Error', and are being caught/logged by elmah and log4net (now filtered out!).

I could write a specific controller and route to handle these non-HTTPS requests as per this question - Responding to HEAD Request in asp.NET MVC 3.

But, from the bots perspective what would be the best response? 200 to show the server is alive, a 302 redirect to the HTTPS url, or stick with the 500 as the site isn't accessible over HTTP?

Community
  • 1
  • 1
Chris
  • 101
  • 1
  • 3
  • 500 doesn't seem right... isn't there a status code for this? 500 suggests there is actually an error somewhere. – Andrew Barber Dec 15 '11 at 17:18
  • 2
    I suggest not throwing a 500 error. If the site is only accessiable via HTTPS. I would use a 301 redirect (permanent) instead of a 302 (temporary). You could also use a rewrite rule to redirect all non-https traffic to https solving the issue. – Nick Bork Dec 15 '11 at 17:19
  • Agree about not throwing the 500 error, but it's the default behaviour of MVC3: `System.InvalidOperationException: The requested resource can only be accessed via SSL. at System.Web.Mvc.RequireHttpsAttribute.HandleNonHttpsRequest(AuthorizationContext filterContext) at System.Web.Mvc.RequireHttpsAttribute.OnAuthorization(AuthorizationContext filterContext) at System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) – Chris Dec 16 '11 at 09:19

2 Answers2

3

You could respond with

405 Method Not Allowed

which means

The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The response MUST include an Allow header containing a list of valid methods for the requested resource.

or with

501 Not Implemented

which means

The server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource.

Personally, I would go with the 405 since it's an error on the client side, a "Hey man, we don't serve that stuff here." seems more appropriate to me than "What the hell are you talking about? I don't understand it." one, the latter is suggested by the the server does not recognize the request method bit of the 501 description.

All the HTTP status codes: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

Albireo
  • 10,977
  • 13
  • 62
  • 96
  • 4
    `405 Method not allowed` is not the right response. Using http instead of https is not using a disallowed method. http(s) is the `scheme` in the URI. The method is the type of request being sent and can be any of `GET`, `HEAD`, `POST`, `PUT`, `DELETE`, `CONNECT`, `OPTIONS`, `TRACE` or `PATCH` (See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods). Throwing a 405 would be telling the client the wrong error occurred. – Fat Monk Nov 28 '18 at 15:19
1

In my case, I was only getting HEAD requests on the root of the site / which seems like bots probing. So, I was a bit worried about returning a 500 or 404.

More on 405

405 may be OK as per Albireo's answer, but you need to return the accepted verbs, something like:

// 405 must include allowable methods.
// https://tools.ietf.org/html/rfc2616#section-14.7
httpContext.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
httpContext.Response.AddHeader( "Allow", "GET" );

302 option

Looking at the comment in the MVC code which does not redirect the HEAD request:

//only redirect for GET requests, otherwise the browser might not propagate the verb and request
//body correctly.

It seems like another option is to send a 302. It should be reasonably safe to return a 302 to the HTTPS site for bot HEAD requests to root (which is what MVC does for a GET). So, I implemented the following which is based on the way that MVC does it:

if( isHead == true && isRoot == true )
{
    httpContext.ClearError();
    httpContext.Response.Clear();                    
    httpContext.Response.StatusCode = 302;
    string url = "https://" + httpContext.Request.Url.Host + httpContext.Request.RawUrl;
    httpContext.Response.Redirect(url, endResponse: false);                    
    return;
}

Implement in global.asax.cs:

protected void Application_Error( object sender, EventArgs e )
{
     //Your code here
}
acarlon
  • 16,764
  • 7
  • 75
  • 94