OdeToCode IC Logo

Policing ActionResults

Wednesday, June 30, 2010

In the previous post we looked at using unit tests and reflection to ensure every controller derived from a specific base class in an ASP.NET MVC application. You might use a base class to ensure action filters are always in place for auditing, logging, or other general purpose security and runtime diagnostics.

You can also use action filters to inspect the result of a controller action. For example, you might want to check the Url of every RedirectResult to preventĀ  open redirects in your application. Spammers love sites with open redirects.

Edit: thanks, Sergio for catching a copy/paste error (update to put the throw inside the if check). Sergio also pointed out the code allows redirects to non-HTTP URIs, and as shown doesn't allow a redirect to a local path (/home/index/123).

public class VerifyRedirects : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var redirect = filterContext.Result as RedirectResult;
        if(redirect != null)
        {
            var host = new Uri(redirect.Url).Host;
            if(_whiteList.Any(host.EndsWith))
            {
                return;
            }            
            throw new InvalidOperationException(BadRedirectMessage);
        }
    }

    string[] _whiteList =
        {
            "microsoft.com", "odetocode.com", "pluralsight.com"
        };

    const string BadRedirectMessage = "...";
}

In this case we are checking the URL against a white list of known destinations. If the host isn't found, the request stops with an exception.