A melhor maneira no asp.net forçar https para um site inteiro?

192

Há cerca de 6 meses, desenvolvi um site em que todas as solicitações precisavam ser feitas em https. A única maneira que encontrei para garantir que todas as solicitações para uma página terminassem em https era verificá-la no evento de carregamento da página. Se a solicitação não tivesse terminado em http, seria response.redirect (" https://example.com ")

Existe uma maneira melhor - idealmente, alguma configuração no web.config?

codethrift
fonte
veja a minha resposta aqui stackoverflow.com/questions/33882350/...
Shady Sherif

Respostas:

250

Por favor, use HSTS (HTTP Strict Transport Security)

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

Resposta original (substituída pela acima em 4 de dezembro de 2015)

basicamente

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

que iria no global.asax.cs (ou global.asax.vb)

Eu não sei de uma maneira de especificá-lo no web.config

John Boker
fonte
7
Isso funciona, mas era perigoso para mim: quando tentei executar localmente no VS 2010 com esse código em execução, minha página inicial nunca foi carregada; acabei de receber uma mensagem "Esta página da web não está disponível". Para corrigir, adicionei uma segunda condição para testar se o URL contém a cadeia "localhost": se não, forçar https.
mg1075
3
Isso está me dando um loop de redirecionamento. Antes de adicionar o código, funcionava bem. Alguma sugestão?
8111 Joe
9
Observe que isso não fornece nenhuma segurança útil. Na verdade, ele só protegerá conexões de usuários que já são seguros e falhará em proteger aqueles que estão sendo atacados (isso ocorre porque um MITM pode simplesmente omitir completamente o redirecionamento e encaminhar tudo para o site "seguro"). IMHO, o redirecionamento de agentes de usuários é apenas uma segurança de vodu agradável e fornece uma ilusão de segurança às vezes perigosa. O único caminho a seguir é instruir os agentes do usuário a solicitar apenas recursos seguros, e não redirecioná-los se não o fizerem. É isso que o HSTS faz - veja as respostas abaixo.
tne
2
Esta resposta deve ser considerada 'prejudicial' e não deve ser usada. Conforme comentário de @tne acima.
Rosdi Kasim 26/03/2015
2
@RosdiKasim Esta resposta ainda deve ser considerada prejudicial desde a edição de 4 de dezembro de 15?
Andrew Morton
123

A outra coisa que você pode fazer é usar o HSTS retornando o cabeçalho "Strict-Transport-Security" ao navegador. O navegador precisa oferecer suporte a isso (e atualmente, é principalmente o Chrome e o Firefox), mas isso significa que, uma vez definido, o navegador não fará solicitações ao site por HTTP e, em vez disso, as converterá em solicitações HTTPS antes de emiti-las . Tente isso em combinação com um redirecionamento do 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;
  }
}

Os navegadores que não estão cientes do HSTS apenas ignoram o cabeçalho, mas ainda são pegos pela instrução switch e enviados para HTTPS.

Troy Hunt
fonte
6
Nunca ouvi falar do cabeçalho do HSTS antes, mas parece bem legal. Existe alguma razão para usar um valor tão pequeno da idade máxima (5 minutos)? O artigo da Wikipedia ao qual você vincula sugere a configuração de um valor alto (6 a 12 meses).
dana 21/02
5
+1. confira este artigo muito extenso no blog de Troy, que inclui detalhes sobre por que apenas o redirecionamento pode reduzir a segurança. Dica: ele pode ficar vulnerável à ferramenta SSL Strip, entre outras coisas. troyhunt.com/2011/11/…
Oran Dennison
3
Também vale a pena conferir o NWebsec , o que torna isso (e mais) muito fácil.
Tieson T.
16
Você deseja envolver a opção if(!Request.IsLocal)para que não interrompa a depuração.
Justin J Stark
1
Boa resposta. Uma sutileza - Para os cabeçalhos Http ("Strict-Transport-Security"), é melhor usar uma biblioteca como o NWebSec porque existem várias opções que estão concentradas em um local de configuração e não espalhadas aqui e ali.
Ognyan Dimitrov
89

O módulo IIS7 permitirá redirecionar.

    <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>
Marca
fonte
12
Além disso, para o IIS 7.0, é necessário instalar o Url Rewrite Module 2.0
Chris
Achei este link simples e útil para fazer com que qualquer página em particular aceite apenas solicitações https - support.microsoft.com/kb/239875
Manik Arora
21

Para aqueles que usam o ASP.NET MVC. Você pode usar o seguinte para forçar SSL / TLS sobre HTTPS em todo o site de duas maneiras:

O jeito difícil

1 - Adicione RequireHttpsAttribute aos filtros globais:

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

2 - Forçar tokens antifalsificação a usar SSL / TLS:

AntiForgeryConfig.RequireSsl = true;

3 - Exija que os cookies exijam HTTPS por padrão, alterando o arquivo Web.config:

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

4 - Use o pacote NWebSec.Owin NuGet e adicione a seguinte linha de código para habilitar o Strict Transport Security em todo o site. Não se esqueça de adicionar a diretiva de pré-carregamento abaixo e enviar seu site para o site de pré-carregamento do HSTS . Mais informações aqui e aqui . Observe que, se você não estiver usando o OWIN, existe um método Web.config que você pode ler no site NWebSec .

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

5 - Use o pacote NWebSec.Owin NuGet e adicione a seguinte linha de código para ativar a Public Key Pinning (HPKP) em todo o site. Mais informações aqui e aqui .

// 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 - Inclua o esquema https em qualquer URL usado. O cabeçalho HTTP da Política de Segurança de Conteúdo (CSP) e o SRI (Subresource Integrity) não são bons quando você imita o esquema em alguns navegadores. É melhor ser explícito sobre HTTPS. por exemplo

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

O caminho fácil

Use o modelo de projeto do ASP.NET MVC Boilerplate Visual Studio para gerar um projeto com tudo isso e muito mais incorporado. Você também pode exibir o código no GitHub .

Muhammad Rehan Saeed
fonte
3
Além disso, se utilizando <authentication mode="Forms">, dentro de você deve ter<forms requireSSL="true">
Plutão
1
@ muhammad-rehan-saeed Estou usando o mvc5 clichê, mas o site não redireciona o http para https automaticamente no servidor de produção, apenas o localhost está faltando alguma coisa?
Diin 31/08/2015
Este não é o fórum certo para fazer esta pergunta. Publique um problema no site do GitHub. O RequireHttpsAttributefaz o redirecionamento. Contanto que você tenha que deve ficar bem.
Muhammad Rehan Saeed
@MuhammadRehanSaeed, adoro sua resposta. Mas ... como obtenho o hash SHA256 de um certificado criado com MakeCert? Tudo o que tenho é uma impressão digital SHA-1 ... Você sabe?
Diana
1
@ Diana, este link pode mostrar como.
Muhammad Rehan Saeed
13

Se você não conseguir configurar isso no IIS por qualquer motivo, eu faria um módulo HTTP que faça o redirecionamento para você:

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

Em seguida, compile-o em uma DLL, adicione-o como referência ao seu projeto e coloque-o no web.config:

 <httpModules>
      <add name="HttpsOnlyModule" type="HttpsOnly.HttpsOnlyModule, HttpsOnly" />
 </httpModules>
FlySwat
fonte
Isso parece mais envolvido do que apenas colocá-lo no mundo todo. Asax - apenas curioso, há uma vantagem?
27715 Brian Brian MacKay
1
A vantagem seria que, quando você não quiser usá-lo, apenas comente o módulo em seu web.config. Esta solução é configurável, enquanto a outra não.
22711 Bob Yexley
2
Estou um pouco confuso. Eu esperava algo como app.BeginRequest += new OnBeginRequest;no Initmétodo e no OnBeginRequestque contém o que o Initmétodo atual contém. Tem certeza de que este módulo funciona conforme o esperado?
Jakub Šturc 6/08/10
Não funciona. Você precisa adicionar o evento OnBeginRequest etc, para que funcione.
SnAzBaZ
Eu editaria esse código defeituoso, mas para torná-lo seguro, você também precisará usar o HSTS. Basta ir com a resposta de Troy Hunt e torná-la um módulo; consulte support.microsoft.com/en-us/kb/307996 (um antigo, mas muito bom).
21478 Marc
4

O que você precisa fazer é:

1) Adicione uma chave dentro do web.config, dependendo do servidor de produção ou estágio, como abaixo

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

2) Dentro do seu arquivo Global.asax, adicione o método abaixo.

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);
            }
        }
    }
}
Chandan Kumar
fonte
3

Se o suporte a SSL não for configurável no seu site (por exemplo, você deve ativar / desativar o https) - você pode usar o atributo [RequireHttps] em qualquer ação do controlador / controlador que deseja proteger.

yarg
fonte
2

Também depende da marca do seu balanceador. Para o mux da web, você precisaria procurar o cabeçalho http X-WebMux-SSL-termination: truepara descobrir que o tráfego recebido era ssl. detalhes aqui: http://www.cainetworks.com/support/redirect2ssl.html

Alexander
fonte
2

Para @ Joe acima, "Isso está me dando um loop de redirecionamento. Antes de adicionar o código, ele funcionava bem. Alguma sugestão? - Joe 8 / Nov / 11 às 4:13"

Isso estava acontecendo comigo também e o que eu acredito que estava acontecendo é que havia um balanceador de carga finalizando a solicitação SSL na frente do servidor Web. Portanto, meu site sempre achava que a solicitação era "http", mesmo que o navegador original solicitasse "https".

Admito que isso é um pouco invasivo, mas o que funcionou para mim foi implementar uma propriedade "JustRedirected" que eu poderia aproveitar para descobrir que a pessoa já foi redirecionada uma vez. Portanto, testo condições específicas que justificam o redirecionamento e, se elas forem atendidas, defino essa propriedade (valor armazenado na sessão) antes do redirecionamento. Mesmo que as condições http / https para redirecionamento sejam atendidas pela segunda vez, ignoro a lógica de redirecionamento e redefino o valor da sessão "JustRedirected" para false. Você precisará de sua própria lógica de teste condicional, mas aqui está uma implementação simples da propriedade:

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

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

Vou jogar meus dois centavos. Se você tiver acesso ao lado do servidor IIS, poderá forçar o HTTPS usando as ligações de protocolo. Por exemplo, você tem um site chamado Blah . No IIS, você configuraria dois sites: Blah e Blah (Redirect) . Para Blah, configure apenas a HTTPSligação (e, FTPse necessário, certifique-se de forçá-la também por uma conexão segura). Para Blah (Redirecionar), configure apenas a HTTPligação. Por fim, na seção Redirecionamento HTTP para Blá (Redirecionar), defina um redirecionamento 301 para a própria pasta raiz, caso contrário, o Web.confighttps://blah.com , com o destino exato ativado. Verifique se cada site no IIS está apontando para elevai ficar tudo ferrado. Verifique também se você HSTSconfigurou no site HTTPSed para que solicitações subsequentes do navegador sejam sempre forçadas a HTTPS e não ocorram redirecionamentos.

Gup3rSuR4c
fonte
2

Esta é uma resposta mais completa baseada no @Troy Hunt's. Adicione esta função à sua WebApplicationturma em 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;
            }
        }
    }

(Para ativar o SSL em sua construção local, ative-o na doca Propriedades do projeto)

noelicus
fonte
1

-> Basta adicionar [RequireHttps] em cima da classe pública HomeController: Controller.

-> E adicione GlobalFilters.Filters.Add (new RequireHttpsAttribute ()); no método 'void protegido Application_Start ()' no arquivo Global.asax.cs.

O que força seu aplicativo inteiro a HTTPS.

Santosh K
fonte
Não acredito que isso funcione para qualquer página veiculada usando WebForms ou APIs criadas com a WebAPI. Abrangerá apenas os controladores MVC.
Marc L.
1

Passei algum tempo procurando as melhores práticas que faziam sentido e encontrei o seguinte que funcionou perfeito para mim. Espero que isso lhe salve algum dia.

Usando o arquivo Config (por exemplo, um site asp.net) https://blogs.msdn.microsoft.com/kaushal/2013/05/22/http-to-https-redirects-on-iis-7-x-and- superior/

ou em seu próprio servidor https://www.sslshopper.com/iis7-redirect-http-to-https.html

[RESPOSTA RESUMIDA] Simplesmente o código abaixo aparece

<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>
Nour Lababidi
fonte
1

No IIS10 (Windows 10 e Server 2016), a partir da versão 1709, existe uma nova opção mais simples para ativar o HSTS para um site.

A Microsoft descreve as vantagens da nova abordagem aqui e fornece muitos exemplos diferentes de como implementar a alteração programaticamente ou editando diretamente o arquivo ApplicationHost.config (semelhante ao web.config, mas opera no nível do IIS, em vez do nível do site individual ) O ApplicationHost.config pode ser encontrado em C: \ Windows \ System32 \ inetsrv \ config.

Eu descrevi dois dos métodos de exemplo aqui para evitar a podridão do link.

Método 1 - Edite o arquivo ApplicationHost.config diretamente Entre as <site>marcas, adicione esta linha:

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

Método 2 - Linha de Comando: Execute o seguinte em um prompt de comando elevado (ou seja, clique com o botão direito do mouse no CMD e execute como administrador). Lembre-se de trocar a Contoso pelo nome do seu site, conforme exibido no Gerenciador do 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

Os outros métodos que a Microsoft oferece nesses artigos podem ser melhores opções se você estiver em um ambiente hospedado em que você tenha acesso limitado.

Lembre-se de que o IIS10 versão 1709 está disponível no Windows 10 agora, mas para o Windows Server 2016 ele está em uma faixa de versão diferente e não será lançado como um patch ou service pack. Veja aqui para detalhes sobre 1709.

Mike
fonte
0

Se você estiver usando o ASP.NET Core, poderá experimentar o pacote de nuget SaidOut.AspNetCore.HttpsWithStrictTransportSecurity.

Então você só precisa adicionar

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

Isso também adicionará o cabeçalho HTTP StrictTransportSecurity a todas as solicitações feitas usando o esquema https.

Exemplo de código e documentação https://github.com/saidout/saidout-aspnetcore-httpswithstricttransportsecurity#example-code

user7755300
fonte