Il modo migliore in asp.net per forzare https per un intero sito?


193

Circa 6 mesi fa ho implementato un sito in cui ogni richiesta doveva essere superiore a HTTPS. L'unico modo in quel momento in cui sono riuscito a trovare per assicurarsi che ogni richiesta a una pagina fosse su https era di controllarlo nell'evento di caricamento della pagina. Se la richiesta non fosse su http vorrei response.redirect (" https://example.com ")

C'è un modo migliore - idealmente qualche impostazione in web.config?



Risposte:


251

Utilizzare HSTS (HTTP Strict Transport Security)

da 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>

Risposta originale (sostituita dalla precedente il 4 dicembre 2015)

fondamentalmente

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

che andrebbe in global.asax.cs (o global.asax.vb)

non conosco un modo per specificarlo in web.config


7
Funziona, ma per me è stato pericoloso: quando ho tentato di eseguire localmente in VS 2010 con questo codice in esecuzione, la mia pagina iniziale non veniva mai caricata; invece, ho appena ricevuto il messaggio "Questa pagina web non è disponibile". Per risolvere, ho aggiunto una seconda condizione per verificare se l'URL contiene la stringa "localhost": in caso contrario, forzare https.
mg1075,

3
Questo mi sta dando un ciclo di reindirizzamento. Prima di aggiungere il codice ha funzionato bene. Eventuali suggerimenti?
Joe,

9
Si noti che ciò non fornisce alcuna sicurezza utile di sorta. In realtà, proteggerà solo le connessioni dagli utenti che sono già sicuri e non riuscirà a proteggere quelli che vengono attaccati (questo perché un MITM può semplicemente omettere del tutto il reindirizzamento e inoltrare tutto al tuo sito "sicuro"). IMHO, il reindirizzamento dei programmi utente è solo una sicurezza voodoo piacevole e fornisce un'illusione a volte pericolosa di sicurezza. L'unico modo per procedere è istruire gli user agent a richiedere solo risorse sicure, non a reindirizzarle in caso contrario. Questo è ciò che fa HSTS: vedere le risposte di seguito.
TNE

2
Questa risposta dovrebbe essere considerata "dannosa" e non dovrebbe essere utilizzata. Come da commento di @tne sopra.
Rosdi Kasim,

2
@RosdiKasim Questa risposta dovrebbe essere ancora considerata dannosa dalla modifica del 4 dicembre 15?
Andrew Morton,

123

L'altra cosa che puoi fare è utilizzare HSTS restituendo l'intestazione "Strict-Transport-Security" al browser. Il browser deve supportare questo (e attualmente lo sono principalmente Chrome e Firefox), ma significa che una volta impostato, il browser non farà richieste al sito su HTTP e le tradurrà invece in richieste HTTPS prima di emetterle . Prova questo in combinazione con un reindirizzamento da 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;
  }
}

I browser che non sono a conoscenza di HSTS ignoreranno semplicemente l'intestazione ma saranno comunque catturati dall'istruzione switch e inviati a HTTPS.


6
Non ho mai sentito parlare dell'intestazione HSTS prima, ma sembra piuttosto bello. C'è qualche motivo per utilizzare un valore di età massima così piccolo (5 minuti)? L'articolo di Wikipedia a cui ti colleghi suggerisce di impostarlo su un valore elevato (6-12 mesi).
dana,

5
+1. consulta questo articolo molto esteso sul blog di Troy che include dettagli sul perché solo l'uso dei reindirizzamenti può ridurre la sicurezza. Suggerimento: può renderti vulnerabile allo strumento Striscia SSL, tra le altre cose. troyhunt.com/2011/11/…
Oran Dennison,

3
Vale anche la pena dare un'occhiata a NWebsec , il che rende questo (e altro) molto semplice.
Tieson T.

16
Ti consigliamo di avvolgere lo switch in if(!Request.IsLocal)modo che non interrompa il debug.
Justin J Stark,

1
Buona risposta. Una sottigliezza: per le intestazioni Http ("Strict-Transport-Security") è meglio usare una libreria come NWebSec perché ci sono più opzioni che sono concentrate in un posto di configurazione piuttosto che sparse qua e là.
Ognyan Dimitrov,

89

Il modulo IIS7 ti permetterà di reindirizzare.

    <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>

12
Inoltre, per IIS 7.0, è necessario installare Url Rewrite Module 2.0
Chris

Ho trovato questo link semplice e utile nel fare in modo che una determinata pagina accetti solo richieste https - support.microsoft.com/kb/239875
Manik Arora,

21

Per coloro che utilizzano ASP.NET MVC. È possibile utilizzare quanto segue per imporre SSL / TLS su HTTPS sull'intero sito in due modi:

The Hard Way

1 - Aggiungi RequireHttpsAttribute ai filtri globali:

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

2 - Forza token anti-contraffazione per utilizzare SSL / TLS:

AntiForgeryConfig.RequireSsl = true;

3 - Richiede i cookie per richiedere HTTPS per impostazione predefinita modificando il file Web.config:

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

4 - Utilizzare il pacchetto NuGet NWebSec.Owin e aggiungere la seguente riga di codice per abilitare Strict Transport Security attraverso il sito. Non dimenticare di aggiungere la direttiva Preload di seguito e inviare il tuo sito al sito HSTS Preload . Maggiori informazioni qui e qui . Si noti che se non si utilizza OWIN, esiste un metodo Web.config che è possibile leggere sul sito NWebSec .

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

5 - Utilizzare il pacchetto NuGet NWebSec.Owin e aggiungere la seguente riga di codice per abilitare Pinning chiave pubblica (HPKP) in tutto il sito. Maggiori informazioni qui e qui .

// 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 - Includi lo schema https negli URL utilizzati. L' intestazione HTTP e l'Integrità delle risorse secondarie (SRI) di Content Security Policy (CSP) non funzionano bene quando si imita lo schema in alcuni browser. È meglio essere espliciti su HTTPS. per esempio

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

Il modo più semplice

Utilizzare il modello di progetto ASP.NET MVC Boilerplate Visual Studio per generare un progetto con tutto questo e molto altro ancora incorporato. È inoltre possibile visualizzare il codice su GitHub .


3
Anche se si utilizza <authentication mode="Forms">, all'interno è necessario disporre di<forms requireSSL="true">
Plutone il

1
@ muhammad-rehan-saeed Sto usando mvc5 boilerplate ma il sito non reindirizza automaticamente http su https sul server di produzione, ma solo su localhost c'è qualcosa che mi manca?
Diin,

Questo non è il forum giusto per porre questa domanda. Pubblica un problema sul sito GitHub. Il RequireHttpsAttributereindirizza. Finché hai che dovrebbe andare bene.
Muhammad Rehan Saeed,

@MuhammadRehanSaeed, ama la tua risposta. Ma ... come posso ottenere l'hash SHA256 di un certificato creato con MakeCert? Tutto quello che ho è un'identificazione personale SHA-1 ... Ti capita di saperlo?
Diana,

1
@Diana questo link può mostrarti come.
Muhammad Rehan Saeed l'

13

Se non riesci a configurarlo in IIS per qualsiasi motivo, creerei un modulo HTTP che esegue il reindirizzamento per te:

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
        }
    }
}

Quindi compilalo in una DLL, aggiungilo come riferimento al tuo progetto e inseriscilo in web.config:

 <httpModules>
      <add name="HttpsOnlyModule" type="HttpsOnly.HttpsOnlyModule, HttpsOnly" />
 </httpModules>

Questo sembra più coinvolto che limitarsi a inserirlo nel global.asax - solo curioso, c'è un vantaggio?
Brian MacKay,

1
Il vantaggio sarebbe, quando non vuoi usarlo, commentare semplicemente il modulo nel tuo web.config. Questa soluzione è configurabile, mentre l'altra no.
Bob Yexley,

2
Sono un po 'confuso. Mi sarei aspettato qualcosa di simile app.BeginRequest += new OnBeginRequest;nel Initmetodo e nel OnBeginRequestche contiene ciò Initche contiene il metodo corrente . Sei sicuro che questo modulo funzioni come previsto?
Jakub Šturc,

Non funziona. È necessario aggiungere l'evento OnBeginRequest ecc., Quindi funziona.
SnAzBaZ,

Modificherei questo codice difettoso, ma per renderlo sicuro dovresti anche usare HSTS. Basta andare con la risposta di Troy Hunt e renderlo un modulo; vedi support.microsoft.com/en-us/kb/307996 (un vecchio, ma buono).
Marc L.

4

Quello che devi fare è:

1) Aggiungere una chiave all'interno di web.config, a seconda del server di produzione o stage come di seguito

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

2) All'interno del tuo file Global.asax aggiungi il metodo seguente.

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

3

Se il supporto SSL non è configurabile nel tuo sito (ad es. Dovrebbe essere in grado di attivare / disattivare https) - puoi utilizzare l'attributo [RequireHttps] su qualsiasi azione controller / controller che desideri proteggere.



2

Per @Joe sopra, "Questo mi sta dando un ciclo di reindirizzamento. Prima di aggiungere il codice ha funzionato bene. Qualche suggerimento? - Joe 8 novembre 11 alle 4:13"

Ciò stava accadendo anche a me e ciò che credo stia accadendo è che c'era un bilanciamento del carico che stava terminando la richiesta SSL di fronte al server Web. Quindi, il mio sito Web ha sempre pensato che la richiesta fosse "http", anche se il browser originale aveva richiesto che fosse "https".

Devo ammettere che è un po 'confuso, ma ciò che ha funzionato per me è stato implementare una proprietà "JustRedirected" che avrei potuto sfruttare per capire che la persona era già reindirizzata una volta. Quindi, collaudo condizioni specifiche che giustificano il reindirizzamento e, se sono soddisfatte, ho impostato questa proprietà (valore memorizzato nella sessione) prima del reindirizzamento. Anche se le condizioni http / https per il reindirizzamento vengono soddisfatte la seconda volta, ignoro la logica di reindirizzamento e reimposto il valore della sessione "JustRedirected" su false. Avrai bisogno della tua logica di test condizionale, ma ecco una semplice implementazione della proprietà:

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

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

2

Ho intenzione di buttare dentro i miei due centesimi. SE hai accesso al lato server IIS, puoi forzare HTTPS usando i binding di protocollo. Ad esempio, hai un sito web chiamato Blah . In IIS avresti impostato due siti: Blah e Blah (Redirect) . Per Blah configura solo il HTTPSbinding (e, FTPse necessario, assicurati di forzarlo anche su una connessione sicura). Per Blah (Redirect) configura solo l' HTTPassociazione. Infine, nella sezione Reindirizzamento HTTP per Blah (Reindirizzamento) assicurati di impostare un reindirizzamento 301 su https://blah.com, con destinazione esatta abilitata. Assicurarsi che ogni sito in IIS stia puntando a esso propria cartella radice, altrimenti Web.config verrà rovinato. Assicurati anche di averloHSTS configurato sul sito HTTPS in modo che le richieste successive da parte del browser siano sempre forzate su HTTPS e non si verifichino reindirizzamenti.


2

Questa è una risposta più completa basata su @Troy Hunt's. Aggiungi questa funzione alla tua WebApplicationclasse in 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;
            }
        }
    }

(Per abilitare SSL sulla build locale abilitarlo nel dock Proprietà per il progetto)


1

-> Aggiungi semplicemente [RequireHttps] in cima alla HomeController di classe pubblica: Controller.

-> E aggiungi GlobalFilters.Filters.Add (new RequireHttpsAttribute ()); nel metodo "protetto void Application_Start ()" nel file Global.asax.cs.

Ciò forza la tua intera applicazione su HTTPS.


Non credo che funzionerà per tutte le pagine pubblicate utilizzando WebForms o qualsiasi API creata con WebAPI. Coprirà solo i controller MVC.
Marc L.

1

Ho trascorso qualche tempo a cercare le migliori pratiche che abbiano un senso e ho trovato quanto segue che ha funzionato perfettamente per me. Spero che questo ti salverà qualche volta.

Utilizzo del file di configurazione (ad esempio un sito Web asp.net) https://blogs.msdn.microsoft.com/kaushal/2013/05/22/http-to-https-redirects-on-iis-7-x-and- più alto/

o sul tuo server https://www.sslshopper.com/iis7-redirect-http-to-https.html

[RISPOSTA CORTA] Semplicemente Il codice qui sotto entra

<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>

1

In IIS10 (Windows 10 e Server 2016), dalla versione 1709 in poi, esiste una nuova opzione più semplice per abilitare HSTS per un sito Web.

Microsoft descrive i vantaggi del nuovo approccio qui , e di fornire molti esempi diversi di come implementare la modifica a livello di codice o modificando direttamente il file ApplicationHost.config (che è come web.config, ma opera a livello IIS, piuttosto che a livello di singolo sito ). ApplicationHost.config è disponibile in C: \ Windows \ System32 \ inetsrv \ config.

Ho delineato due dei metodi di esempio qui per evitare il marciume dei link.

Metodo 1 - Modifica direttamente il file ApplicationHost.config Tra i <site>tag, aggiungi questa riga:

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

Metodo 2 - Riga di comando: eseguire quanto segue da un prompt dei comandi con privilegi elevati (ad es. Mouse destro su CMD ed eseguire come amministratore). Ricorda di scambiare Contoso con il nome del tuo sito come appare in Gestione 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

Gli altri metodi offerti da Microsoft in quegli articoli potrebbero essere opzioni migliori se ti trovi in ​​un ambiente ospitato in cui hai accesso limitato.

Tieni presente che IIS10 versione 1709 è ora disponibile su Windows 10, ma per Windows Server 2016 si trova su una traccia di rilascio diversa e non verrà rilasciato come patch o service pack. Vedi qui per i dettagli sul 1709.


0

Se si utilizza ASP.NET Core, è possibile provare il pacchetto nuget SaidOut.AspNetCore.HttpsWithStrictTransportSecurity.

Quindi devi solo aggiungere

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

Questo aggiungerà anche l'intestazione HTTP StrictTransportSecurity a tutte le richieste fatte usando lo schema https.

Codice di esempio e documentazione https://github.com/saidout/saidout-aspnetcore-httpswithstricttransportsecurity#example-code

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.