1

If my site receives a GET request for a URL with "potentially dangerous" characters, e.g.:

http://example.com/unsafe:)

then the user gets a response that looks like the server had an error (specifically, the server choked on the "A potentially dangerous Request.Path value was detected from the client" HttpException). And, worse, the user doesn't get my custom error page (Views/Shared/Error.cshtml) because the global HandleErrorAttribute doesn't see this particular "error". So the user gets the generic "something is broken but I won't tell you what it is, nya nya nya!" page.

I want to change this response so that the user gets something that looks like my site's 404 page ("can't find the page you're asking for"), but with an HTTP 400 response code.

As near as I can tell, the only place to try to handle this particular exception is in the Global.asax Application_Error routine. (My custom global HandleErrorAttribute doesn't see the exception.)

Any help or guidance (or a sharp slap on the wrist for trying to do something I shouldn't be trying to do) would be appreciated!

FYI, here is my existing Global.asax code:

    /// <summary> Handle "page not found" (HTTP 404) errors. </summary>
    protected void Application_EndRequest()
    {
        // This code is from: http://stackoverflow.com/a/9026941/1637105
        if (Context.Response.StatusCode == 404) {
            Response.Clear();

            var rd = new RouteData();
            rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
            rd.Values["controller"] = "Errors";
            rd.Values["action"] = "NotFound";

            IController c = new ErrorsController();
            c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
        }
    }

    protected void Application_Error(object sender, EventArgs e)
    {
        // Convert "A potentially dangerous Request.Path value was detected from the client" to an HTTP 404 (page not found) response
        var ex = Server.GetLastError();
        if (ex != null && ex is HttpException) {
            var re = new Regex(@"(?ix: \b potentially \b.+?\b dangerous \b.+?\b value \b.+?\b detected \b.+?\b client \b )");
            if (re.IsMatch(ex.Message)) {
                // <Convert the response to 404>
            }
        }
    }

EDIT:

I should add that I have elmah wired up and happy, so I get emails several times a week when the bad guys ping my site with

/w00tw00t.at.blackhats.romanian.anti-sec:)

This whole exercise came about when I decided to suppress the elmah emails, and I discovered that more benign requests that happen to contain "dangerous" characters result in the user getting a really ugly web page that looks like my website is broken.

Suppressing the elmah email is easy. I guess I'm asking if I'm going about this the right way by detecting the error in the Application_Error routine, and, if so, what is a reasonably proper thing to do about in that routine.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Bob.at.Indigo.Health
  • 11,023
  • 13
  • 64
  • 111
  • Have you seen this: http://stackoverflow.com/questions/619895/how-can-i-properly-handle-404-in-asp-net-mvc – David Tansey Jul 13 '14 at 23:11
  • When I try a URL like the one you provided I get an `HTTP 400`. Is that what you get? – Rowan Freeman Jul 13 '14 at 23:16
  • @RowanFreeman Ok, so I just learned something, thanks! Yes, I get a 400 (bad request syntax), which is technically more correct than 404 (not found). But the non-malicious user just wants to know that the requested page isn't there; he doesn't care that the request is syntactically incorrect. OTOH, the bad guys regularly ping my site with bogus requests. Returning 404 rather than 400 might make 'em think that I'm not being vigilant about dangerous URLs and encourage them to pay more attention to my site. – Bob.at.Indigo.Health Jul 13 '14 at 23:47
  • @DavidTansey Thanks, I've seen that. The accepted answer uses basically the same code that I have in my Application_EndRequest to take a trip back through a controller to display the page. Thanks you you and RowanFreeman, I think I have a better idea of the question I'm asking... I'll update the question... – Bob.at.Indigo.Health Jul 13 '14 at 23:50
  • If : is the only character causing you trouble, just allow it. Read this http://stackoverflow.com/questions/2831142/asp-net-4-url-limitations-why-url-cannot-contain-any-3f-characters – ScottE Jul 14 '14 at 00:28

2 Answers2

0

I always try to have exceptions logged, most of them are not important, but still it's good to see them. Create, or better use existing error handling library (http://msdn.microsoft.com/en-us/library/aa479332.aspx).

In your case I would use ELMAH to handle them, write to log file/database and show custom error page to user giving him some error id, and option to contact support.

Hanselman spoke about ELMAH long time ago: http://www.hanselman.com/blog/ELMAHErrorLoggingModulesAndHandlersForASPNETAndMVCToo.aspx

You would have something like this:

  1. Instll ELMAH with nugget
  2. Add to filters in your web project
  3. Just add to your web config redirections for errors. Example

    <customErrors mode="On" defaultRedirect="~/Home/Error">
    <error statusCode="404" redirect="~/Home/ErrorBadUrl" />
    </customErrors>
    

You can act on ErrorLog_Logged event in global.asax if you need ot tidy up things.

Additional: I used to create Elmah filter, but not sure it is neccessary, just in case this is example code:

public class ElmahErrorFilter : IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        // Long only handled exceptions, because all other will be caught by ELMAH anyway.
        if (filterContext.ExceptionHandled)
            ErrorSignal.FromCurrentContext().Raise(filterContext.Exception);
    }
}

EDIT: And if you are not interested in logging errors, you can use IIS customer error pages (http://www.iis.net/configreference/system.webserver/httperrors).

MiBu
  • 869
  • 8
  • 17
  • And just to add to why I was confused and asked the question in the first place, I DO specify `` in my web.config. But apparently, because this "error" is not caught by the global HandleErrorAttribute (which is responsible for displaying the custom error page) I get the generic, ugly "something is broken but we won't tell you what it is" page. – Bob.at.Indigo.Health Jul 14 '14 at 00:14
0

Ok, so now I think I understand that the infamous "dangerous value received from client" results in an HTTP 400, which I can handle exactly the same way I handle HTTP 404 results: Display the "page not found" view, but preserve the HTTP status code.

A slight tweak to my existing error handling code seems to do just what I want it to do:

    /// <summary> Handle "page not found" (HTTP 404) and "dangerous/invalid syntax" (HTTP 400) errors. </summary>
    protected void Application_EndRequest()
    {
        // This code is adapted from: https://stackoverflow.com/a/9026941/1637105
        var code = Context.Response.StatusCode;
        if (code == 404 || code == 400) {
            Response.Clear();

            var rd = new RouteData();
            rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
            rd.Values["controller"] = "Errors";
            rd.Values["action"] = "NotFound";

            IController c = new ErrorsController();
            c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
        }
    }

And the associated controller code (also adapted from https://stackoverflow.com/a/9026941/1637105):

public class ErrorsController : Controller
{
    /// <summary> GET: /Errors/NotFound </summary>
    public ActionResult NotFound()
    {
        object model = Request.Url.PathAndQuery;

        if (!Request.IsAjaxRequest()) {
            return View(model);
        } else {
            return PartialView("_NotFound", model);
        }
    }
}

and, of course, you need an associated view in Views/Errors/NotFound.cshtml.

Note that, in the context of this question, I've removed the Application_Error routine, which contributes nothing to this answer.

But apparently I'll need to use the Application_Error handler if I want robust redirection of errors (including errors that occur outside of the MVC pipeline). But that's a subject for another question another day.

Community
  • 1
  • 1
Bob.at.Indigo.Health
  • 11,023
  • 13
  • 64
  • 111