ASP.NET MVC: OutputCache attribute disregards RequireHttps attribute?

1.2k views Asked by At

I have an ASP.NET MVC 3 application with an action that uses both the RequireHttps and OutputCache attributes:

[RequireHttps]
[OutputCache(Duration = 14400, VaryByCustom = "CurrentUser"]
public ActionResult VersionB()
{
  return View();
}

When I navigate to that page, I get redirected to HTTPS, as expected.

However, after that initial page load, I can still access the page via HTTP. If I remove the OutputCache attribute, I can no longer access the page via HTTP.

It seems as if the OutputCache disregards HTTPS, thus allowing insecure access to the page. Is it even possible to cache an action that is served over HTTPS?

1

There are 1 answers

1
Darin Dimitrov On BEST ANSWER

The [RequireHttps] attribute implementation is flawed and doesn't take into account caching.

Here's a fix:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class MyRequireHttpsAttribute : RequireHttpsAttribute
{
    protected virtual bool AuthorizeCore(HttpContextBase httpContext)
    {
        return httpContext.Request.IsSecureConnection;
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (!AuthorizeCore(filterContext.HttpContext))
        {
            this.HandleNonHttpsRequest(filterContext);
        }
        else
        {
            var cache = filterContext.HttpContext.Response.Cache;
            cache.SetProxyMaxAge(new TimeSpan(0L));
            cache.AddValidationCallback(this.CacheValidateHandler, null);
        }
    }

    private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
    {
        validationStatus = this.OnCacheAuthorization(new HttpContextWrapper(context));
    }

    protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
    {
        if (!AuthorizeCore(httpContext))
        {
            return HttpValidationStatus.IgnoreThisRequest;
        }
        return HttpValidationStatus.Valid;
    }
}

and then:

[MyRequireHttps]
[OutputCache(Duration = 14400, VaryByCustom = "CurrentUser"]
public ActionResult VersionB()
{
    return View();
}