¿La mejor manera en asp.net para forzar https para un sitio completo?

192

Hace unos 6 meses, implementé un sitio donde cada solicitud tenía que estar por encima de https. La única forma en el momento en que pude encontrar para asegurarme de que cada solicitud a una página fuera a través de https era verificarla en el evento de carga de la página. Si la solicitud no fuera superior a http, respondería.redirect (" https://example.com ")

¿Hay una mejor manera, idealmente alguna configuración en web.config?

codethrift
fuente
mira mi respuesta aquí stackoverflow.com/questions/33882350/…
Shady Sherif
Publicación relacionada - Cómo forzar HTTPS usando un archivo web.config
RBT

Respuestas:

250

Utilice HSTS (Seguridad de transporte estricta de HTTP)

de http://www.hanselman.com/blog/HowToEnableHTTPStrictTransportSecurityHSTSInIIS7.aspx

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="HTTP to HTTPS redirect" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
                        redirectType="Permanent" />
                </rule>
            </rules>
            <outboundRules>
                <rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
                    <match serverVariable="RESPONSE_Strict_Transport_Security"
                        pattern=".*" />
                    <conditions>
                        <add input="{HTTPS}" pattern="on" ignoreCase="true" />
                    </conditions>
                    <action type="Rewrite" value="max-age=31536000" />
                </rule>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>

Respuesta original (reemplazada por la anterior el 4 de diciembre de 2015)

básicamente

protected void Application_BeginRequest(Object sender, EventArgs e)
{
   if (HttpContext.Current.Request.IsSecureConnection.Equals(false) && HttpContext.Current.Request.IsLocal.Equals(false))
   {
    Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"]
+   HttpContext.Current.Request.RawUrl);
   }
}

eso iría en global.asax.cs (o global.asax.vb)

No conozco una forma de especificarlo en web.config

John Boker
fuente
77
Esto funciona, pero fue peligroso para mí: cuando intenté ejecutar localmente en VS 2010 con este código en ejecución, mi página de inicio nunca se cargó; en su lugar, acabo de recibir el mensaje "Esta página web no está disponible". Para solucionarlo, agregué una segunda condición para probar si la url contiene la cadena "localhost": si no es así, entonces fuerce https.
mg1075
3
Esto me está dando un bucle de redireccionamiento. Antes de agregar el código funcionó bien. ¿Alguna sugerencia?
Joe
9
Tenga en cuenta que esto no proporciona ningún tipo de seguridad útil. En realidad, solo protegerá las conexiones de los usuarios que ya están seguros y no podrá proteger a los que están siendo atacados (esto se debe a que un MITM simplemente puede omitir la redirección por completo y reenviar todo a su sitio "seguro"). En mi humilde opinión, la redirección de los agentes de usuario es solo una seguridad vudú para sentirse bien, y proporciona una ilusión de seguridad a veces peligrosa. La única forma de hacerlo es instruir a los agentes de usuario para que solo soliciten recursos seguros, no los redirijan si no lo hacen. Esto es lo que hace HSTS: vea las respuestas a continuación.
TNE
2
Esta respuesta debe considerarse 'dañina' y no debe usarse. Según el comentario de @tne arriba.
Rosdi Kasim
2
@RosdiKasim ¿Debería esta respuesta considerarse aún dañina desde la edición del 4 de diciembre de 2015?
Andrew Morton
123

La otra cosa que puede hacer es usar HSTS devolviendo el encabezado "Strict-Transport-Security" al navegador. El navegador debe admitir esto (y en la actualidad, lo hacen principalmente Chrome y Firefox), pero significa que una vez configurado, el navegador no realizará solicitudes al sitio a través de HTTP y en su lugar las traducirá a solicitudes HTTPS antes de emitirlas. . Pruebe esto en combinación con una redirección desde HTTP:

protected void Application_BeginRequest(Object sender, EventArgs e)
{
  switch (Request.Url.Scheme)
  {
    case "https":
      Response.AddHeader("Strict-Transport-Security", "max-age=300");
      break;
    case "http":
      var path = "https://" + Request.Url.Host + Request.Url.PathAndQuery;
      Response.Status = "301 Moved Permanently";
      Response.AddHeader("Location", path);
      break;
  }
}

Los navegadores que no son conscientes de HSTS simplemente ignorarán el encabezado pero aún así serán atrapados por la declaración de cambio y enviados a HTTPS.

Troy Hunt
fuente
66
Nunca escuché sobre el encabezado HSTS antes, pero se ve muy bien. ¿Hay alguna razón para usar un valor de edad máxima tan pequeño (5 minutos)? El artículo de Wikipedia al que se vincula sugiere configurarlo en un valor grande (6-12 meses).
dana
55
+1. Echa un vistazo a este artículo muy extenso en el blog de Troy que incluye detalles sobre por qué solo el uso de redireccionamientos puede reducir la seguridad. Sugerencia: puede dejarlo vulnerable a la herramienta SSL Strip, entre otras cosas. troyhunt.com/2011/11/…
Oran Dennison
3
También vale la pena echarle un vistazo a NWebsec , lo que hace que esto (y más) sea muy fácil.
Tieson T.
16
Deberá ajustar el interruptor if(!Request.IsLocal)para que no interrumpa la depuración.
Justin J Stark
1
Buena respuesta. Una sutileza: para los encabezados Http ("Strict-Transport-Security") es mejor usar una biblioteca como NWebSec porque hay múltiples opciones que se concentran en un lugar de configuración en lugar de extenderse aquí y allá.
Ognyan Dimitrov
89

El módulo IIS7 le permitirá redirigir.

    <rewrite>
        <rules>
            <rule name="Redirect HTTP to HTTPS" stopProcessing="true">
                <match url="(.*)"/>
                <conditions>
                    <add input="{HTTPS}" pattern="^OFF$"/>
                </conditions>
                <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther"/>
            </rule>
        </rules>
    </rewrite>
marca
fuente
12
Además, para IIS 7.0, debe instalar Url Rewrite Module 2.0
Chris
Encontré este enlace simple y útil para hacer que cualquier página en particular acepte solo solicitudes https - support.microsoft.com/kb/239875
Manik Arora
21

Para aquellos que usan ASP.NET MVC. Puede usar lo siguiente para forzar SSL / TLS a través de HTTPS en todo el sitio de dos maneras:

El camino difícil

1 - Agregue RequireHttpsAttribute a los filtros globales:

GlobalFilters.Filters.Add(new RequireHttpsAttribute());

2 - Forzar tokens antifalsificación para usar SSL / TLS:

AntiForgeryConfig.RequireSsl = true;

3 - Exigir que las cookies requieran HTTPS de forma predeterminada cambiando el archivo Web.config:

<system.web>
    <httpCookies httpOnlyCookies="true" requireSSL="true" />
</system.web>

4 - Use el paquete NWebSec.Owin NuGet y agregue la siguiente línea de código para habilitar Strict Transport Security en todo el sitio. No olvide agregar la directiva de precarga a continuación y enviar su sitio al sitio de precarga de HSTS . Más información aquí y aquí . Tenga en cuenta que si no está utilizando OWIN, hay un método Web.config que puede leer en el sitio NWebSec .

// app is your OWIN IAppBuilder app in Startup.cs
app.UseHsts(options => options.MaxAge(days: 30).Preload());

5 - Use el paquete NWebSec.Owin NuGet y agregue la siguiente línea de código para habilitar la fijación de clave pública (HPKP) en todo el sitio. Más información aquí y aquí .

// app is your OWIN IAppBuilder app in Startup.cs
app.UseHpkp(options => options
    .Sha256Pins(
        "Base64 encoded SHA-256 hash of your first certificate e.g. cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
        "Base64 encoded SHA-256 hash of your second backup certificate e.g. M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=")
    .MaxAge(days: 30));

6 - Incluya el esquema https en cualquier URL utilizada. El encabezado HTTP de la Política de seguridad de contenido (CSP) y la Integridad de recursos secundarios (SRI) no funcionan bien cuando se imita el esquema en algunos navegadores. Es mejor ser explícito sobre HTTPS. p.ej

<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.4/bootstrap.min.js"></script>

La manera fácil

Use la plantilla de proyecto ASP.NET MVC Boilerplate Visual Studio para generar un proyecto con todo esto y mucho más integrado. También puede ver el código en GitHub .

Muhammad Rehan Saeed
fuente
3
Además, si se usa <authentication mode="Forms">, debe tener dentro<forms requireSSL="true">
Plutón
1
@ muhammad-rehan-saeed Estoy usando mvc5 repetitivo pero el sitio no redirige http a https automáticamente en el servidor de producción, lo hace solo en localhost ¿hay algo que me falta?
Diin
Este no es el foro adecuado para hacer esta pregunta. Publique un problema en el sitio de GitHub. El RequireHttpsAttributehace la redirección. Mientras tengas eso, debería estar bien.
Muhammad Rehan Saeed
@ Muhammad RehanSaeed, me encanta tu respuesta. Pero ... ¿cómo obtengo el hash SHA256 de un certificado creado con MakeCert? Todo lo que tengo es una huella digital SHA-1 ... ¿Sabes?
Diana
1
@Diana este enlace puede mostrarte cómo.
Muhammad Rehan Saeed
13

Si no puede configurar esto en IIS por cualquier razón, crearía un módulo HTTP que haga la redirección por usted:

using System;
using System.Web;

namespace HttpsOnly
{
    /// <summary>
    /// Redirects the Request to HTTPS if it comes in on an insecure channel.
    /// </summary>
    public class HttpsOnlyModule : IHttpModule
    {
        public void Init(HttpApplication app)
        {
            // Note we cannot trust IsSecureConnection when 
            // in a webfarm, because usually only the load balancer 
            // will come in on a secure port the request will be then 
            // internally redirected to local machine on a specified port.

            // Move this to a config file, if your behind a farm, 
            // set this to the local port used internally.
            int specialPort = 443;

            if (!app.Context.Request.IsSecureConnection 
               || app.Context.Request.Url.Port != specialPort)
            {
               app.Context.Response.Redirect("https://" 
                  + app.Context.Request.ServerVariables["HTTP_HOST"] 
                  + app.Context.Request.RawUrl);    
            }
        }

        public void Dispose()
        {
            // Needed for IHttpModule
        }
    }
}

Luego, compílelo en un archivo DLL, agréguelo como referencia a su proyecto y colóquelo en web.config:

 <httpModules>
      <add name="HttpsOnlyModule" type="HttpsOnly.HttpsOnlyModule, HttpsOnly" />
 </httpModules>
FlySwat
fuente
Esto parece más complicado que simplemente incluirlo en el global.asax. Es curioso, ¿hay alguna ventaja?
Brian MacKay el
1
La ventaja sería que, cuando no quiera usarlo, simplemente comente el módulo en su web.config. Esta solución es configurable, mientras que la otra no.
Bob Yexley
2
Estoy un poco confundido Esperaba algo así como app.BeginRequest += new OnBeginRequest;en el Initmétodo y en el OnBeginRequestque contiene qué corrienteInit que contiene el método . ¿Estás seguro de que este módulo funciona como se esperaba?
Jakub Šturc
No funciona. Es necesario agregar el evento OnBeginRequest, etc., entonces funciona.
SnAzBaZ el
Editaría este código defectuoso, pero para hacerlo seguro también necesitaría usar HSTS. Simplemente vaya con la respuesta de Troy Hunt y conviértalo en un módulo; ver support.microsoft.com/en-us/kb/307996 (un viejo, pero bueno).
Marc L.
4

Lo que debes hacer es:

1) Agregue una clave dentro de web.config, dependiendo de la producción o el servidor de escenario como se muestra a continuación

<add key="HttpsServer" value="stage"/>
             or
<add key="HttpsServer" value="prod"/>

2) Dentro de su archivo Global.asax agregue el siguiente método.

void Application_BeginRequest(Object sender, EventArgs e)
{
    //if (ConfigurationManager.AppSettings["HttpsServer"].ToString() == "prod")
    if (ConfigurationManager.AppSettings["HttpsServer"].ToString() == "stage")
    {
        if (!HttpContext.Current.Request.IsSecureConnection)
        {
            if (!Request.Url.GetLeftPart(UriPartial.Authority).Contains("www"))
            {
                HttpContext.Current.Response.Redirect(
                    Request.Url.GetLeftPart(UriPartial.Authority).Replace("http://", "https://www."), true);
            }
            else
            {
                HttpContext.Current.Response.Redirect(
                    Request.Url.GetLeftPart(UriPartial.Authority).Replace("http://", "https://"), true);
            }
        }
    }
}
Chandan Kumar
fuente
3

Si el soporte SSL no es configurable en su sitio (es decir, debería poder activar / desactivar https), puede usar el atributo [RequireHttps] en cualquier controlador / acción de controlador que desee asegurar.

yarg
fuente
2

Para @Joe arriba, "Esto me está dando un bucle de redirección. Antes de agregar el código funcionó bien. ¿Alguna sugerencia? - Joe Nov 8 '11 a las 4:13"

Esto también me estaba sucediendo a mí y lo que creo que estaba sucediendo es que había un equilibrador de carga que finalizaba la solicitud SSL frente al servidor web. Por lo tanto, mi sitio web siempre pensaba que la solicitud era "http", incluso si el navegador original solicitaba que fuera "https".

Admito que esto es un poco extraño, pero lo que funcionó para mí fue implementar una propiedad "JustRedirected" que podría aprovechar para descubrir que la persona ya fue redirigida una vez. Por lo tanto, pruebo las condiciones específicas que justifican la redirección y, si se cumplen, establezco esta propiedad (valor almacenado en la sesión) antes de la redirección. Incluso si las condiciones http / https para la redirección se cumplen la segunda vez, omito la lógica de redirección y restablezco el valor de sesión "JustRedirected" a falso. Necesitará su propia lógica de prueba condicional, pero aquí hay una implementación simple de la propiedad:

    public bool JustRedirected
    {
        get
        {
            if (Session[RosadaConst.JUSTREDIRECTED] == null)
                return false;

            return (bool)Session[RosadaConst.JUSTREDIRECTED];
        }
        set
        {
            Session[RosadaConst.JUSTREDIRECTED] = value;
        }
    }
Paul Schroeder
fuente
2

Voy a tirar mis dos centavos. SI tiene acceso al lado del servidor IIS, puede forzar HTTPS mediante el uso de enlaces de protocolo. Por ejemplo, tiene un sitio web llamado Blah . En IIS, configuraría dos sitios: Blah y Blah (Redirect) . Para Blah, solo configure el HTTPSenlace (y FTPsi es necesario, asegúrese de forzarlo también a través de una conexión segura). Para Blah (Redirect) solo configure el HTTPenlace. Por último, en la sección HTTP Redirect para la Blah (Redirect), de lo asegúrese de establecer una redirección 301 a https://blah.com, con el destino exacto habilitado. Asegúrese de que cada sitio en IIS señale que espropia carpeta raíz, de lo contrario, el Web.config se arruinará. También asegúrese de haberHSTS configurado en su sitio HTTPS para que las solicitudes posteriores del navegador siempre se vean obligadas a HTTPS y no se produzcan redireccionamientos.

Gup3rSuR4c
fuente
2

Esta es una respuesta más completa basada en @Troy Hunt's. Agregue esta función a su WebApplicationclase en Global.asax.cs:

    protected void Application_BeginRequest(Object sender, EventArgs e)
    {
        // Allow https pages in debugging
        if (Request.IsLocal)
        {
            if (Request.Url.Scheme == "http")
            {
                int localSslPort = 44362; // Your local IIS port for HTTPS

                var path = "https://" + Request.Url.Host + ":" + localSslPort + Request.Url.PathAndQuery;

                Response.Status = "301 Moved Permanently";
                Response.AddHeader("Location", path);
            }
        }
        else
        {
            switch (Request.Url.Scheme)
            {
                case "https":
                    Response.AddHeader("Strict-Transport-Security", "max-age=31536000");
                    break;
                case "http":
                    var path = "https://" + Request.Url.Host + Request.Url.PathAndQuery;
                    Response.Status = "301 Moved Permanently";
                    Response.AddHeader("Location", path);
                    break;
            }
        }
    }

(Para habilitar SSL en su compilación local, habilítelo en el Dock de Propiedades para el proyecto)

noelicus
fuente
1

-> Simplemente AGREGAR [RequireHttps] en la parte superior de la clase pública HomeController: Controlador.

-> Y agregue GlobalFilters.Filters.Add (nuevo RequireHttpsAttribute ()); en el método 'vacío protegido Application_Start ()' en el archivo Global.asax.cs.

Lo que obliga a toda su aplicación a HTTPS.

Santosh K
fuente
No creo que esto funcione para ninguna página servida usando WebForms o cualquier API construida con WebAPI. Solo cubrirá los controladores MVC.
Marc L.
1

Pasé algún tiempo buscando las mejores prácticas que tengan sentido y encontré lo siguiente que funcionó perfectamente para mí. Espero que esto te salve alguna vez.

Uso del archivo de configuración (por ejemplo, un sitio web asp.net) https://blogs.msdn.microsoft.com/kaushal/2013/05/22/http-to-https-redirects-on-iis-7-x-and- mayor/

o en su propio servidor https://www.sslshopper.com/iis7-redirect-http-to-https.html

[RESPUESTA CORTA] Simplemente el siguiente código va dentro

<system.webServer> 
 <rewrite>
     <rules>
       <rule name="HTTP/S to HTTPS Redirect" enabled="true" 
           stopProcessing="true">
       <match url="(.*)" />
        <conditions logicalGrouping="MatchAny">
        <add input="{SERVER_PORT_SECURE}" pattern="^0$" />
       </conditions>
       <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" 
        redirectType="Permanent" />
        </rule>
       </rules>
 </rewrite>
Nour Lababidi
fuente
1

En IIS10 (Windows 10 y Server 2016), desde la versión 1709 en adelante, hay una nueva opción más simple para habilitar HSTS para un sitio web.

Microsoft describe las ventajas del nuevo enfoque aquí , y proporciona muchos ejemplos diferentes de cómo implementar el cambio mediante programación o editando directamente el archivo ApplicationHost.config (que es como web.config pero funciona a nivel de IIS, en lugar de a nivel de sitio individual) ) ApplicationHost.config se puede encontrar en C: \ Windows \ System32 \ inetsrv \ config.

He esbozado dos de los métodos de ejemplo aquí para evitar la pudrición del enlace.

Método 1 : edite el archivo ApplicationHost.config directamente Entre las <site>etiquetas, agregue esta línea:

<hsts enabled="true" max-age="31536000" includeSubDomains="true" redirectHttpToHttps="true" />

Método 2 : línea de comandos: ejecute lo siguiente desde un símbolo del sistema elevado (es decir, el mouse derecho en CMD y ejecútelo como administrador). Recuerde cambiar Contoso con el nombre de su sitio como aparece en el Administrador de IIS.

c:
cd C:\WINDOWS\system32\inetsrv\
appcmd.exe set config -section:system.applicationHost/sites "/[name='Contoso'].hsts.enabled:True" /commit:apphost
appcmd.exe set config -section:system.applicationHost/sites "/[name='Contoso'].hsts.max-age:31536000" /commit:apphost
appcmd.exe set config -section:system.applicationHost/sites "/[name='Contoso'].hsts.includeSubDomains:True" /commit:apphost
appcmd.exe set config -section:system.applicationHost/sites "/[name='Contoso'].hsts.redirectHttpToHttps:True" /commit:apphost

Los otros métodos que ofrece Microsoft en esos artículos podrían ser mejores opciones si se encuentra en un entorno alojado donde tiene acceso limitado.

Tenga en cuenta que IIS10 versión 1709 está disponible en Windows 10 ahora, pero para Windows Server 2016 está en una pista de lanzamiento diferente, y no se lanzará como un parche o paquete de servicio. Ver aquí para más detalles sobre 1709.

Miguel
fuente
0

Si está utilizando ASP.NET Core, puede probar el paquete nuget SaidOut.AspNetCore.HttpsWithStrictTransportSecurity.

Entonces solo necesitas agregar

app.UseHttpsWithHsts(HttpsMode.AllowedRedirectForGet, configureRoutes: routeAction);

Esto también agregará el encabezado HTTP StrictTransportSecurity a todas las solicitudes realizadas utilizando el esquema https.

Código de ejemplo y documentación https://github.com/saidout/saidout-aspnetcore-httpswithstricttransportsecurity#example-code

usuario7755300
fuente