2015-04-06 23 views
33

Jaki jest zalecany sposób przekierowania do HTTPS wszystkich przychodzących żądań, które nie są bezpieczne. Czy muszę napisać komponent oprogramowania pośredniego? Jeśli tak, nie mogłem wymyślić, jak uzyskać nazwę serwera.Przekierowanie do 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); 
     } 
    } 
} 

Odpowiedz

41

Można użyć własnej klasy middleware, ale zwykle po prostu zrobić coś takiego w mojej konfiguracji startowej:

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

Co to robi jest po prostu chwycić całą URL, ciąg kwerendy i wszystko, i użyj GetComponents, aby uzyskać wszystko pod adresem z wyjątkiem schematu. Następnie schemat HTTPS zostanie dodany do adresu URL komponentu.

To będzie pracować z pełną .NET Framework, ASP.NET dla rdzenia, można zrobić coś takiego:

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

ten dołącza hosta i ścieżkę do programu HTTPS. Możesz także dodać inne komponenty, takie jak zapytanie i hash.

+0

Masz rację, to nie działa z rdzeniem. Ale zmiana na to działało: var withHttps = "https: //" + context.Request.Host + context.Request.Path; – William

+0

Ponieważ jest to tak proste, wygląda na to, że powinna istnieć prosta .RequireHttps() w wbudowanej bibliotece. – William

+0

Czy istnieje sposób sprawdzenia, jaki jest port HTTPS? Zazwyczaj będzie to oczywiście 443, ale w środowisku programistycznym, gdzie, powiedzmy, korzystasz z IIS Express, Visual Studio zwykle ustawia port SSL na coś takiego jak 44300. W takim przypadku, czy ten fragment kodu nie przekieruje do niewłaściwego adresu URL? Znaczenie: 'http: // localhost: 5900' stanie się' https: // localhost: 5900', gdy powinno być 'https: // localhost: 44300'. Jakikolwiek sposób, aby uniknąć twardego kodowania numeru portu? –

17

Innym sposobem, który preferuję, jest użycie atrybutu/filtra [RequireHttps]. Można to zrobić zarówno do kontrolerów:

[RequireHttps] 
public class AccountController { 
} 

albo ten w Startup.cs w ConfigureServices:

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

Również chciałem tylko dodać, że odpowiedź vcsjones' jest również poprawna, ale musisz koniecznie dodać ten kod na wczesnym etapie konfiguracji, przed jakimkolwiek innym oprogramowaniem pośredniczącym/kodem, które powoduje przekierowania. W moim przypadku dodałem go tuż przed dodaniem oprogramowania warstwy pośredniej Identity Framework.

+4

Jedynym lekkim minusem dla tego z MVC jest to, że stosuje * tylko * do MVC. Jeśli mówisz, masz 'services UseStaticFiles()' przed MVC (tak jak powinieneś, statyczna zawartość nie powinna przechodzić przez potok MVC) wtedy przekierowanie nie nastąpi. – vcsjones

4

Jeśli chcesz pobrać port, gdy znajdujesz się w środowisku DEV w .NET Core, spójrz na env.IsDevelopment() i warunkowo chwyć port SSL z 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"); 
} 

`

Po grabing port SSL, można włączyć port w roztworze wysłana przez @vcsjones.

13

Pełną odpowiedź jest numerem 1, ale nie kończą konfigurowania protokołu HTTPS, należy przejść dodatkowy krok:

1 - Następnie używamy RequireHttpsAttribute przekierowanie do HTTPS i ustawić port SSL w opcjach MVC . Odczytujemy także port SSL z launchSettings.json, ale potrzebujemy go tylko w trybie programowania.

2 - Użyj AddAntiforgery, aby wymagać protokołu HTTPS na tokenach zapobiegających fałszerstwu.

3 - Użyj pakietu NuGet NWebsec.AspNetCore.Middleware i UseHsts, aby włączyć Strict Transport Security (HSTS) w całym serwisie. Nie zapomnij dodać obciążenia wstępnego poniżej i prześlij swoją witrynę pod numer HSTS Preload site. Więcej informacji: here i here.

4 - Użyj pakietu NWebsec.AspNetCore.Middleware NuGet i metody UseHpkp, aby włączyć publiczne przypinanie klawiszy (HPKP) w całym serwisie. Zauważ, że jeśli popełnisz błąd w tym, to w zasadzie Zrobisz swoją stronę.Więcej informacji: here i here.

5 - Uwzględnij schemat https w dowolnym użytym adresie URL. Content Security Policy (CSP) Nagłówek HTTP i Subresource Integrity (SRI) nie grają dobrze, gdy naśladujesz schemat w niektórych przeglądarkach. Lepiej mówić otwarcie o HTTPS. na przykład

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

6- Użyj ASP.NET MVC Boilerplate programu Visual Studio projektu szablonu, aby wygenerować projekt z tego wszystkiego i znacznie więcej zbudowany w. Można również wyświetlić kod na GitHub.

Po wszystkich wyżej wymienionych, klasa Startup powinien wyglądać mniej więcej tak:

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

Mam zmodyfikowany nieco @vcsjones odpowiedzieć w użyciu niestandardowego portu w środowisku dev. Również kredyty do @ 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); 
    } 
}); 

Należy zauważyć, że port powinien być zaczerpnięte z launchSettings.json pliku więc należy również dodać ten plik do ConfigurationBuilder w 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

Istnieje kilka świetnych odpowiedzi tutaj, ale potrzebowałem rozwiązania, które działałoby z lub bez IIS, a także nie zmieniało protokołu podczas lokalnego debugowania. Dodałem to zaraz po dodaniu uwierzytelniania AD do potoku w metodzie Startup.Configure. To jest dla pełnej ramy. Inne rozwiązania tutaj opisują, jak odbudować adres URL 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

W celu uzyskania aplikacji DotNet Core uruchomić pod HTTPS, istnieją trzy kroki do naśladowania:

  1. Przejdź do pliku launchSettings.json swoją aplikację i wpisz port HTTPS z 44390- 44399 enter image description here
  2. Edytuj plik Startup.cs. Wprowadź następujący kod:

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

    enter image description here

  3. prawym przyciskiem myszy na katalogu głównym projektu, z Solution Explorer i wybierz Właściwości. Zaznacz opcję Włącz SSL, skopiuj łącze SSL i dodaj je do obszaru adresu URL aplikacji. enter image description here

    1. Uruchom aplikację. Zawsze będzie działał w kontekście HTTPS.
+0

Wystąpił błąd podczas próby określenia identyfikatora procesu AwsomeApp.exe, który hostuje aplikację. Wystąpił jeden lub więcej błędów. –

+0

Próbowałem tego na miejscu i działało dobrze. – maximdumont

0

Jedna technika omówiona na https://github.com/aspnet/KestrelHttpServer/issues/916 jest dodanie tego do swojej sieci.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

Lubię atrybut z dyrektywą kompilatora

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