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?
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();
}