2015-04-06 18 views
33

Qual è il modo consigliato per reindirizzare a HTTPS tutte le richieste in entrata che non sono sicure. Devo scrivere un componente middleware? Se è così, non sono riuscito a capire come ottenere il nome del server.Reindirizza a HTTPS

public class RedirectHttpMiddleware 
{ 
    RequestDelegate _next; 

    public RedirectHttpMiddleware(RequestDelegate next) 
    { 
     _next = next; 
    } 

    public async Task Invoke(HttpContext context) 
    { 
     if (context.Request.IsSecure) 
      await _next(context); 
     else 
     { 
      var server = ""; // How do I get the server name? 
      context.Response.Redirect("https://" + server + context.Request.Path); 
     } 
    } 
} 

risposta

41

È possibile utilizzare la propria classe middleware, ma in genere ho solo fare qualcosa di simile nella mia configurazione di avvio:

app.Use(async (context, next) => 
{ 
    if (context.Request.IsHttps) 
    { 
     await next(); 
    } 
    else 
    { 
     var withHttps = Uri.UriSchemeHttps + Uri.SchemeDelimiter + context.Request.Uri.GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Scheme, UriFormat.SafeUnescaped); 
     context.Response.Redirect(withHttps); 
    } 
}); 

Quello che fa è solo afferrare l'URL intero, stringa di query e tutti, e utilizzare GetComponents per ottenere tutto eccetto lo lo schema nell'URL. Quindi lo schema HTTPS viene anteposto all'URL dei componenti.

Ciò funzionerà con la versione completa di .NET Framework, ASP.NET per core, si può fare qualcosa di simile:

app.Use(async (context, next) => 
{ 
    if (context.Request.IsHttps) 
    { 
     await next(); 
    } 
    else 
    { 
     var withHttps = "https://" + context.Request.Host + context.Request.Path; 
     context.Response.Redirect(withHttps); 
    } 
}); 

Questo aggiunge il host e il percorso per lo schema HTTPS. Potresti voler aggiungere anche altri componenti come la query e l'hash.

+0

Lei ha ragione, non ha funzionato con anima. Ma modificandolo ha funzionato: var withHttps = "https: //" + context.Request.Host + context.Request.Path; – William

+0

Essendo così semplice, sembra che ci dovrebbe essere un semplice .RequireHttps() nella libreria integrata. – William

+0

C'è un modo per verificare qual è la porta HTTPS? In genere, ovviamente, sarebbe 443, ma in un ambiente di sviluppo in cui, diciamo, stai usando IIS Express, in genere Visual Studio imposta la porta SSL su qualcosa come 44300. In tal caso, questo snippet di codice non verrebbe reindirizzato all'URL errato? Il significato, 'http: // localhost: 5900' diventerebbe' https: // localhost: 5900' quando dovrebbe essere 'https: // localhost: 44300'. Un modo per evitare di codificare il numero di porta? –

17

Un altro modo che preferisco è utilizzare l'attributo/filtro [RequireHttps]. È possibile fare questo per i controller:

[RequireHttps] 
public class AccountController { 
} 

Altrimenti questo nella vostra Startup.cs in ConfigureServices:

services.Configure<MvcOptions>(options => 
{ 
    options.Filters.Add(new RequireHttpsAttribute()); 
} 

Inoltre, volevo solo aggiungere che la risposta vcsjones' è anche corretto, ma devi assicurarti di aggiungere questo codice subito nella configurazione, prima di qualsiasi altro middleware/codice che causa reindirizzamenti. Nel mio caso, l'ho aggiunto poco prima che aggiungessi il middleware di Identity Framework.

+4

L'unico piccolo svantaggio di ciò con MVC è che applica * solo * a MVC. Se dici, hai 'services.UseStaticFiles()' prima di MVC (come dovresti, il contenuto statico non dovrebbe passare attraverso la pipeline MVC), quindi il reindirizzamento non avverrà. – vcsjones

4

Se si desidera acquisire la porta quando si trova in un ambiente DEV in .NET Core, consultare env.IsDevelopment() e afferrare in modo condizionale la porta SSL da launchSettings.json.

if (env.IsDevelopment()) 
{ 
    var builder = new ConfigurationBuilder() 
     .SetBasePath(env.ContentRootPath) 
     .AddJsonFile(@"Properties/launchSettings.json", optional: false, reloadOnChange: true); 
    var launchConfig = builder.Build(); 
    sslPort = launchConfig.GetValue<int>("iisSettings:iisExpress:sslPort"); 
} 

`

Dopo grabing la porta SSL, quindi è possibile incorporare la porta nella soluzione postato da @vcsjones.

13

La risposta completa è nel numero 1, ma non si fermano qui la creazione di HTTPS, andare il passo in più:

1 - Abbiamo quindi utilizzare il RequireHttpsAttribute per reindirizzare a HTTPS e impostare la porta SSL nelle opzioni MVC . Stiamo anche leggendo la porta SSL da launchSettings.json ma ne abbiamo solo bisogno in modalità Sviluppo.

2 - Utilizzare AddAntiforgery per richiedere HTTPS sui token anti-contraffazione.

3 - Utilizzare il pacchetto NuGet NWebsec.AspNetCore.Middleware e il metodo UseHsts per abilitare la sicurezza del trasporto (HSTS) attraverso il sito. Non dimenticare di aggiungere il precarico qui sotto e di inviare il tuo sito allo HSTS Preload site. Maggiori informazioni here e here.

4 - Utilizzare il pacchetto NuGet NWebsec.AspNetCore.Middleware e il metodo UseHpkp per abilitare Public Key Pinning (HPKP) attraverso il sito. Nota che se commetti un errore con questo stai essenzialmente facendo il tuo sito.Maggiori informazioni here e here.

5 - Includere lo schema https in qualsiasi URL utilizzato. Content Security Policy (CSP) L'intestazione HTTP e Subresource Integrity (SRI) non funzionano correttamente 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> 

6- utilizzano Visual Studio modello di progetto ASP.NET MVC Boilerplate per generare un progetto con tutto questo e molto di più costruito. È inoltre possibile visualizzare il codice a GitHub.

Dopo tutto quanto sopra, la classe Startup dovrebbe essere simile a questa:

public class Startup 
{ 
    private readonly int? sslPort; 

    public Startup(IHostingEnvironment hostingEnvironment) 
    { 
     if (hostingEnvironment.IsDevelopment()) 
     { 
      var launchConfiguration = new ConfigurationBuilder() 
       .SetBasePath(hostingEnvironment.ContentRootPath) 
       .AddJsonFile(@"Properties\launchSettings.json") 
       .Build(); 
      // During development we won't be using port 443. 
      this.sslPort = launchConfiguration.GetValue<int>("iisSettings:iisExpress:sslPort"); 
     } 
    } 

    public void ConfigureServices(IServiceCollection services) 
    { 
     services 
      .AddAntiforgery(options => 
      { 
       options.RequireSsl = true; 
      }); 
      .AddMvc(options => 
      { 
       options.Filters.Add(new RequireHttpsAttribute()); 
       options.SslPort = sslPort; 
      }); 
    } 

    public void Configure(IApplicationBuilder application) 
    { 
     application 
      .UseHsts(options => options.MaxAge(days: 18 * 7).IncludeSubdomains().Preload()) 
      .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: 18 * 7) 
       .IncludeSubdomains()) 
      .UseCsp(options => options 
       .UpgradeInsecureRequests(this.sslPort.HasValue ? this.sslPort.Value : 443)) 
      .UseMvc(); 
    } 
} 
2

ho modificato un po '@vcsjones rispondere per utilizzare la porta personalizzata in ambiente dev. Anche crediti per @ long2know.

app.Use(async (context, next) => 
{ 
    var request = context.Request; 

    if (request.IsHttps) 
    { 
     await next(); 
    } 
    else 
    { 
     var devPort = Configuration.GetValue<int>("iisSettings:iisExpress:sslPort"); 

     var host = env.IsDevelopment() 
      ? new HostString(request.Host.Host, devPort) 
      : new HostString(request.Host.Host); 

     string newUrl = $"https://{host}{request.PathBase}{request.Path}{request.QueryString}"; 
     context.Response.Redirect(newUrl, true); 
    } 
}); 

Nota che la porta dovrebbe essere presa dal launchSettings.json file in modo si dovrebbe anche aggiungere questo file ConfigurationBuilder nella Startup.cs:

.AddJsonFile(@"Properties/launchSettings.json", optional: false, reloadOnChange: true)

3

AlwaysHttpsMiddleware.cs, inspired by RequiresHttpsAttribute.

using System; 
using System.Threading.Tasks; 
using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Mvc; 

public class AlwaysHttpsMiddleware 
{ 
    private readonly RequestDelegate _next; 

    public AlwaysHttpsMiddleware(RequestDelegate next) 
    { 
     _next = next; 
    } 

    public async Task Invoke(HttpContext context) 
    { 
     if (context.Request.IsHttps) 
     { 
      await _next.Invoke(context); 
     } 
     else 
     { 
      var request = context.Request; 

      // only redirect for GET requests, otherwise the browser might 
      // not propagate the verb and request body correctly. 

      if (!string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase)) 
      { 
       context.Response.StatusCode = StatusCodes.Status403Forbidden; 
       await context.Response.WriteAsync("This site requires HTTPS."); 
      } 
      else 
      { 
       var newUrl = string.Concat(
        "https://", 
        request.Host.ToUriComponent(), 
        request.PathBase.ToUriComponent(), 
        request.Path.ToUriComponent(), 
        request.QueryString.ToUriComponent()); 

       context.Response.Redirect(newUrl); 
      } 
     } 
    } 
} 

Startup.cs

public void Configure(IApplicationBuilder app) 
{ 
    if (_env.IsProduction()) 
    { 
     app.UseMiddleware<AlwaysHttpsMiddleware>(); 
    } 
} 
1

Ci sono alcune grandi risposte qui, ma avevo bisogno di una soluzione che funzionasse con o senza IIS e che non cambiasse il protocollo durante il debug locale. L'ho aggiunto subito dopo aver aggiunto l'autorizzazione AD alla pipeline nel metodo Startup.Configure. Questo è per la struttura completa. Altre soluzioni qui illustrano come ricostruire l'URL per Core.

app.Use(async (context, next) => 
{ 
    if (context.Request.IsHttps || // Handles https straight to the server 
     context.Request.Headers["X-Forwarded-Proto"] == Uri.UriSchemeHttps || // Handles an IIS or Azure passthrough 
     context.Request.Host.ToString().StartsWith("localhost",true, System.Globalization.CultureInfo.InvariantCulture) || // Ignore for localhost 
     context.Request.Headers["X-Forwarded-Proto"].Contains(Uri.UriSchemeHttps)) // X-Forwarded-Proto can have multiple values if there are multiple proxies 
    { 
     await next(); 
    } 
    else 
    { 
     var withHttps = Uri.UriSchemeHttps + Uri.SchemeDelimiter + context.Request.Host + context.Request.Path + context.Request.QueryString; 
     context.Response.Redirect(withHttps); 
    } 
}); 
1

Al fine di avere la vostra applicazione dotnet Nucleo per l'esecuzione in HTTPS, ci sono tre passi da seguire:

  1. Accedere al file di launchSettings.json del dall'applicazione e immettere la porta https desiderata 44390- 44399 enter image description here
  2. Modifica il file Startup.cs. Inserire il codice seguente:

    services.Configure<MvcOptions>(options => 
    { 
        options.SslPort = 44390; 
        options.Filters.Add(new RequireHttpsAttribute()); 
    }); 
    

    enter image description here

  3. fare clic destro sul vostro progetto della directory radice, da Esplora soluzioni e selezionare Proprietà. Seleziona Abilita SSL, copia il collegamento SSL e aggiungilo all'area URL dell'app. enter image description here

    1. Avviare l'applicazione. Funzionerà sempre nel contesto HTTPS.
+0

Si è verificato un errore nel tentativo di determinare l'ID del processo di AwsomeApp.exe che ospita la tua applicazione. Si sono verificati uno o più errori. –

+0

L'ho provato localmente e ha funzionato bene. – maximdumont

0

Una tecnica discusso https://github.com/aspnet/KestrelHttpServer/issues/916 è l'aggiunta di questo per il vostro Web.config:

<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}/{R:1}" redirectType="Permanent" /> 
      </rule> 
     </rules> 
</rewrite> 
0

mi piace attributo con direttiva del compilatore

#if !DEBUG 
    [RequireHttps] 
#endif 
    public class HomeController : Controller 
    { 
    } 
Problemi correlati