Forzare un sito MVC di ASP.NET al protocollo HTTPS

Hyper Text Transfer Protocol Secure (HTTPS)

è la versione protetta di HTTP, il protocollo su cui i dati vengono inviati tra il browser e il sito a cui si è connessi. La ‘S’ alla fine di HTTPS significa ‘Secure’. Significa che tutte le comunicazioni tra il tuo browser e il sito web sono crittografate.

Alcuni motivi per passare al protocollo HTTPS:

  • HTTPS protegge l’integrità del tuo sito web
  • HTTPS protegge la privacy dei tuoi utenti
  • HTTPS protegge la sicurezza degli utenti
  • HTTPS è anche utilizzato da Google come fattore di rango – vantaggio SEO
  • Più probabilità di convertire gli utenti quando le loro informazioni sono sicure.

ASP.NET MVC [RequireHttps]

ASP.NET MVC consente di applicare un attributo [RequireHttps] sui singoli controller. Consente inoltre di applicare l’attributo globalmente aggiungendo codice nell’ Application_Start nel Global.asax.

Dovrete creare/aggiornare la classe FilterConfig

public class FilterConfig
  {
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
           var requireHttps = new RequireHttpsAttribute();
           filters.Add(requireHttps);
    }
  }

Ed aggiungere il codice nel global.asax:

public class Global : HttpApplication
  {
    protected void Application_Start()
    {
      AreaRegistration.RegisterAllAreas();
      RouteConfig.RegisterRoutes(RouteTable.Routes);
      FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    }
  }

Il problema con il RequireHttpsAttribute è che di defaul restituisce un http status 302 che indica un redirect temporaneo (vedi lista http status codes) invece per evitare problemi SEO dovremmo restituire un http status 301 che indica un redirect permanente. Ci sono diverse soluzioni in base alla versione utilizzata.

Con MVC, precedente a ASP.NET 5.2.4 dobbiamo scrivere la nostra versione del RequireHttpsAttribute:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, 
                  Inherited = true, 
                  AllowMultiple = false)]
  public class MyRequireHttpsAttribute : RequireHttpsAttribute
  {
    protected override void HandleNonHttpsRequest(
      AuthorizationContext filterContext)
    {
      var request = filterContext.HttpContext.Request;
      var host = request.Url.Host.ToLower();
      var port = string.Empty;
      var rawUrl = request.RawUrl;
      string secureUrl;

      // TODO: modificare il codice in base all'ambiente di dev locale
      if ((new string[] { "127.0.0.1", 
                          "localhost", 
                          "mylocalwebsite.it" }).Contains(host))
      {
          host = "mylocalwebsite.it";
        //port = ":40497";
      }

      secureUrl = "https://" + host + port + rawUrl;

      filterContext.Result = new RedirectResult(secureUrl, 
                                                permanent: true);
    }
  }

Quindi modificare il nel FilterConfig:

public class FilterConfig
  {
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
           filters.Add(new MyRequireHttpsAttribute);
    }
  }

Se si utilizza MVC, da ASP.NET 5.2.4 è possibile emettere un HTTP 301 anziché un HTTP 302 nel modo seguente:

public class FilterConfig
  {
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
           filters.Add(new RequireHttpsAttribute(permanent: true));
    }
  }