Перенаправление на HTTPS

Каков рекомендуемый способ перенаправления 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);
        }
    }
}

Ответ 1

Вы можете использовать свой собственный класс промежуточного программного обеспечения, но обычно я просто делаю что-то подобное в моей конфигурации запуска:

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

Что это значит, просто захватите весь URL, строку запроса и все, и используйте GetComponents, чтобы получить все, кроме схемы в URL. Затем схема HTTPS добавляется к URL-адресу компонентов.

Это будет работать с полной платформой .NET Framework для ядра ASP.NET, вы можете сделать что-то вроде этого:

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

Это добавляет хост и путь к схеме HTTPS. Вы можете также добавить другие компоненты, такие как запрос и хеш.

Ответ 2

Другим способом, который я предпочитаю, является использование атрибута/фильтра [RequireHttps]. Вы можете либо сделать это для своих контроллеров:

[RequireHttps]
public class AccountController {
}

Или иначе это в вашем Startup.cs в ConfigureServices:

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

Кроме того, я просто хотел добавить, что ответ vcsjones также верен, но вы должны обязательно добавить этот код на раннем этапе в своей конфигурации перед любым другим промежуточным программным обеспечением/кодом, который вызывает перенаправления. В моем случае я добавил его непосредственно перед тем, как добавить промежуточное программное обеспечение Identity Framework.

Ответ 3

Полный ответ - в номере 1, но не останавливайте там настройку HTTPS, выполните дополнительный шаг:

1 - Затем мы используем RequireHttpsAttribute для перенаправления на HTTPS и установки порта SSL в параметрах MVC. Мы также читаем порт SSL из launchSettings.json, но нам это нужно только в режиме разработки.

2 - Используйте AddAntiforgery, чтобы потребовать HTTPS на ваших токенах подделки.

3 - Используйте пакет NWebsec.AspNetCore.Middleware NuGet и UseHsts, чтобы включить Strict Transport Security (HSTS) по всему сайту. Не забудьте добавить Preload ниже и отправить свой сайт на сайт HSTS Preload. Подробнее здесь и здесь.

4 - Используйте пакет NWebsec.AspNetCore.Middleware NuGet и метод UseHpkp, чтобы включить привязку открытого ключа (HPKP) по всему сайту. Обратите внимание, что если вы ошиблись с этим, вы, по сути, делаете DoS'ing своего сайта. Подробнее здесь и здесь.

5 - Включите схему https в любом используемом URL. Политика безопасности контента (CSP) Заголовок HTTP и Целостность субресурсов (SRI) не очень приятны, когда вы имитируете схемы в некоторых браузерах. Лучше говорить о HTTPS. например.

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

6- Используйте ASP.NET MVC Boilerplate Шаблон проекта Visual Studio для создания проекта со всем этим и многое другое. Вы также можете просмотреть код на GitHub.

После всего вышесказанного ваш класс Startup должен выглядеть примерно так:

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

Ответ 4

Если вы хотите захватить порт, когда находитесь в среде DEV в .NET Core, посмотрите env.IsDevelopment() и условно захватите порт SSL из 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");
}

`

После захвата SSL-порта вы можете включить порт в решение, отправленное @vcsjones.

Ответ 5

AlwaysHttpsMiddleware.cs, вдохновленный 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>();
    }
 }

Ответ 6

Я изменил бит @vcsjones на использование пользовательского порта в среде dev. Также кредиты @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);
    }
});

Обратите внимание, что порт должен быть взят из файла launchSettings.json, поэтому вы также должны добавить этот файл в ConfigurationBuilder в Startup.cs:

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

Ответ 7

Здесь есть несколько отличных ответов, но мне нужно решение, которое будет работать с IIS или без него, а также не изменять протокол во время локальной отладки. Я добавил это сразу после добавления AD auth к конвейеру в методе Startup.Configure. Это для полной структуры. Другие решения здесь описывают, как перестроить URL для ядра.

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

Ответ 8

Чтобы ваше приложение DOTNet Core работало под HTTPS, необходимо выполнить следующие шаги:

  • Перейдите в файл приложения launchSettings.json и введите желаемый порт https с 44390-44399 введите описание изображения здесь
  • Отредактируйте файл Startup.cs. Введите следующий код:

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

    введите описание изображения здесь

  • Щелкните правой кнопкой мыши на своем корневом каталоге проекта, в обозревателе решений и выберите "Свойства". Установите флажок Включить SSL, Скопируйте ссылку SSL и добавьте ее в область URL-адреса приложения. введите описание изображения здесь

    1. Запустите приложение. Он всегда будет работать в контексте HTTPS.

Ответ 9

Один метод, обсуждаемый в https://github.com/aspnet/KestrelHttpServer/issues/916, добавляет это в ваш 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>

Ответ 10

Мне нравится атрибут с директивой компилятора

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