web-dev-qa-db-fra.com

ASP.NET Core 2.1 sans redirection HTTP / HTTPS dans App Engine

Problème

Je n'ai pas pu obtenir que la redirection automatique de HTTP vers HTTPS fonctionne correctement lorsque l'application est publiée sur App Engine.

Lorsque j'accède au site Web via example.com le site a été acheminé vers http://www.example.com et que la connexion n'est pas sécurisée. Lorsque j'accède au site Web via https://www.example.com le site Web est ensuite correctement sécurisé avec SSL géré par Google. Cependant, la redirection automatique de HTTP vers HTTPS ne se produit pas.

Insecured connection

J'ai également reçu une erreur dans la visionneuse de journaux avertissant que Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware lançait Impossible de déterminer le port https pour la redirection.

enter image description here

J'ai suivi la documentation de MSDN et je ne la fais fonctionner que localement, mais pas lorsque l'application est publiée sur App Engine. https://docs.Microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-2.1&tabs=visual-studio

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory logger)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseStatusCodePages();
        app.UseExceptionHandler("/Error");
        app.UseHsts(); // This was added by the template
    }

    app.UseHttpsRedirection(); // This was added by the template
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseAuthentication();
    app.UseMvc();
}

Voici le Program.cs. Fondamentalement par défaut à partir du modèle de projet

public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
    return WebHost.CreateDefaultBuilder(args)
        .CaptureStartupErrors(true)
        .UseStartup<Startup>();
}

App.yaml utilisé pour le déploiement

runtime: aspnetcore
env: flexible
automatic_scaling:
  min_num_instances: 1
  max_num_instances: 20
  cpu_utilization:
    target_utilization: 0.8
readiness_check:
  path: "/readinesscheck"
  check_interval_sec: 5
  timeout_sec: 4
  failure_threshold: 2
  success_threshold: 2
  app_start_timeout_sec: 300
liveness_check:
  path: "/livenesscheck"
  check_interval_sec: 30
  timeout_sec: 4
  failure_threshold: 2
  success_threshold: 2
skip_files:
  - node_modules/
  - wwwroot/src/vendor/
  - ^(.*/)?.*\.pdb$
  - ^(.*/)?.*\.log$

Ce que j'ai essayé était le suivant (un seul à la fois)

  1. AddHttpsRedirection Middleware à la méthode ConfigureServices.

Ce qui s'est soldé par une application inaccessible (erreur 502 Server).

services.AddHttpsRedirection(options =>
{
    options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
    options.HttpsPort = 443;
});
  1. Ajouter EnvironmentVariable à app.yaml

En outre, l'application a été inaccessible (erreur de serveur 502).

env_variables:
   ASPNETCORE_HTTPS_PORT: "443"
  1. Configuration manuelle du port HTTPS dans Program.cs

A également fini avec l'application inaccessible (erreur 502 Server).

WebHost.CreateDefaultBuilder(args)
    .UseSetting("https_port", "8080") // also return 502 when port is 443
  1. Configurez ForwardedHeaderOptions dans la méthode ConfigureServices et utilisez ForwardedHeaderOptions dans la méthode Configure. https://docs.Microsoft.com/en-us/aspnet/core/Host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1#other-proxy-server-and-load- scénarios-balancer

L'application est accessible mais pas de redirection HTTP/HTTPS automatique.

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = 
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

app.UseForwardedHeaders();
  1. Exposition manuelle des ports 443 et 8080 dans Dockerfile.

L'application est accessible mais pas de redirection HTTP/HTTPS automatique. Je comprends que lors de l'exécution dans app.yaml est défini sur aspnetcore . Le processus de publication a généré automatiquement son propre Dockerfile qui est utilisé pour déployer l'application sur App Engine.

EXPOSE 443
EXPOSE 8080
10

D'une manière ou d'une autre, j'ai réussi à le faire fonctionner après avoir créé mon propre middleware qui recherche l'en-tête " X-Forwarded-Proto " selon cet indice sur Microsoft et App Engine documentation.

Microsoft: Le middleware d'en-têtes transférés doit être activé pour qu'une application puisse traiter les en-têtes transférés avec UseForwardedHeaders.

App Engine: Les connexions SSL sont interrompues au niveau de l'équilibreur de charge. Le trafic provenant de l'équilibreur de charge est envoyé à l'instance via un canal chiffré, puis transmis au serveur d'applications via HTTP. L'en-tête X-Forwarded-Proto vous permet de comprendre si la demande d'origine était HTTP ou HTTPs.

Microsoft exige que le middleware soit activé avant le démarrage de l'application pour traiter les en-têtes transférés

Configurez donc les options du middleware dans la méthode ConfigureServices

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = 
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

et l'utiliser dans la méthode Configure avant toute autre chose

app.UseForwardedHeaders();

Ensuite, écrire le middleware personnalisé qui lit les en-têtes transférés et redirige vers HTTPS, y compris les requêtes.

Dans Configurez la méthode

app.Use(async (context, next) =>
{
    if (context.Request.IsHttps || context.Request.Headers["X-Forwarded-Proto"] == Uri.UriSchemeHttps)
    {
        await next();
    }
    else
    {
        string queryString = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : string.Empty;
        var https = "https://" + context.Request.Host + context.Request.Path + queryString;
        context.Response.Redirect(https);
    }
});

Au final, la méthode Configure ressemble à ceci

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseForwardedHeaders();
    app.Use(async (context, next) =>
    {
        if (context.Request.IsHttps || context.Request.Headers["X-Forwarded-Proto"] == Uri.UriSchemeHttps)
        {
            await next();
        }
        else
        {
            string queryString = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : string.Empty;
            var https = "https://" + context.Request.Host + context.Request.Path + queryString;
            context.Response.Redirect(https);
        }
    });

    if (env.IsDevelopment())
    {
        // code removed for clarity
    }
    else
    {
        // code removed for clarity
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    // code removed for clarity
    app.UseMvc();
}

Maintenant, accédez à example.com redirigez-moi directement https://www.example.com

9

Le schéma peut être défini manuellement dans Startup.Configure avant d'utiliser tout type de middleware:

app.Use((context, next) =>
{
    context.Request.Scheme = "https";
    return next();
});
0
A. Morel