Najlepszy sposób w asp.net, aby wymusić https dla całej witryny?

192

Około 6 miesięcy temu stworzyłem witrynę, na której każde żądanie musiało przekraczać https. W tej chwili mogłem tylko upewnić się, że każde żądanie strony przekroczyło https, aby sprawdzić to w przypadku ładowania strony. Jeśli żądanie nie dotyczyło http, odpowiedziałbym. Odpowiedź.redirect („ https://example.com ”)

Czy istnieje lepszy sposób - najlepiej jakieś ustawienie w pliku web.config?

codethrift
źródło
sprawdź moją odpowiedź tutaj stackoverflow.com/questions/33882350/…
Shady Sherif

Odpowiedzi:

250

Proszę użyć HSTS (HTTP Strict Transport Security)

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

Oryginalna odpowiedź (zastąpiona powyższą w dniu 4 grudnia 2015 r.)

gruntownie

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

poszedłby w global.asax.cs (lub global.asax.vb)

nie wiem, jak to określić w pliku web.config

John Boker
źródło
7
Działa to, ale było dla mnie niebezpieczne: kiedy próbowałem uruchomić lokalnie w VS 2010 z uruchomionym tym kodem, moja strona początkowa nigdy się nie ładowała; zamiast tego właśnie otrzymałem komunikat „Ta strona jest niedostępna”. Aby to naprawić, dodałem drugi warunek, aby sprawdzić, czy adres URL zawiera ciąg „localhost”: jeśli nie, wymuś https.
mg1075,
3
To daje mi pętlę przekierowania. Przed dodaniem kodu działało dobrze. Jakieś sugestie?
Joe,
9
Należy pamiętać, że nie zapewnia to żadnego przydatnego bezpieczeństwa. W rzeczywistości zabezpieczy tylko połączenia użytkowników, które są już bezpieczne, i nie zabezpieczy atakowanych (dzieje się tak, ponieważ MITM może po prostu całkowicie pominąć przekierowanie i przekazać wszystko do „bezpiecznej” strony). IMHO przekierowywanie agentów użytkownika to po prostu dobre samopoczucie bezpieczeństwa i zapewnia czasami niebezpieczne złudzenie bezpieczeństwa. Jedynym sposobem jest poinstruowanie agentów użytkownika, aby żądali tylko bezpiecznych zasobów, a nie przekierowywać ich, jeśli nie. Tak właśnie działa HSTS - patrz odpowiedzi poniżej.
tne
2
Tę odpowiedź należy uznać za „szkodliwą” i nie należy jej używać. Zgodnie z komentarzem @tne powyżej.
Rosdi Kasim
2
@RosdiKasim Czy ta odpowiedź powinna być nadal uważana za szkodliwą od czasu edycji z 4 grudnia 2015 r.?
Andrew Morton
123

Inną rzeczą, którą możesz zrobić, to użyć HSTS , zwracając nagłówek „Strict-Transport-Security” do przeglądarki. Przeglądarka musi to obsługiwać (obecnie to przede wszystkim Chrome i Firefox), ale oznacza to, że po ustawieniu przeglądarka nie będzie wysyłać żądań do witryny przez HTTP i zamiast tego przetłumaczy je na żądania HTTPS przed ich wydaniem . Wypróbuj to w połączeniu z przekierowaniem z 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;
  }
}

Przeglądarki, które nie rozpoznają HSTS, po prostu zignorują nagłówek, ale nadal zostaną złapane przez instrukcję switch i wysłane do HTTPS.

Troy Hunt
źródło
6
Nigdy wcześniej nie słyszałem o nagłówku HSTS, ale wygląda całkiem fajnie. Czy jest jakiś powód, aby używać tak małej wartości maksymalnego wieku (5 minut)? Artykuł w Wikipedii, do którego linkujesz, sugeruje ustawienie dużej wartości (6-12 miesięcy).
dana
5
+1. zapoznaj się z tym bardzo obszernym artykułem na blogu Troya, który zawiera szczegółowe informacje na temat tego, dlaczego stosowanie przekierowań może zmniejszyć bezpieczeństwo. Wskazówka: może narazić Cię na niebezpieczeństwo między innymi narzędzie Strip Strip. troyhunt.com/2011/11/…
Oran Dennison
3
Warto również sprawdzić NWebsec , co czyni to (i więcej) bardzo łatwym.
Tieson T.
16
Będziesz chciał owinąć przełącznik, if(!Request.IsLocal)aby nie przerywał debugowania.
Justin J Stark,
1
Dobra odpowiedź. Jedna subtelność - w przypadku nagłówków HTTP („Strict-Transport-Security”) lepiej jest używać biblioteki takiej jak NWebSec, ponieważ istnieje wiele opcji skoncentrowanych w jednym miejscu konfiguracji, a nie rozłożonych tu i tam.
Ognyan Dimitrov
89

Moduł IIS7 umożliwia przekierowanie.

    <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>
znak
źródło
12
Ponadto w przypadku usług IIS 7.0 należy zainstalować moduł Url Rewrite 2.0
Chris
Uznałem, że ten link jest prosty i pomocny w tym, aby każda konkretna strona akceptowała tylko żądania https - support.microsoft.com/kb/239875
Manik Arora
21

Dla osób korzystających z ASP.NET MVC. Aby wymusić obsługę protokołu SSL / TLS przez HTTPS w całej witrynie, można użyć dwóch następujących metod:

Trudna droga

1 - Dodaj RequireHttpsAttribute do filtrów globalnych:

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

2 - Wymuś używanie tokenów zapobiegających fałszerstwom do korzystania z SSL / TLS:

AntiForgeryConfig.RequireSsl = true;

3 - Wymagaj, aby pliki cookie wymagały domyślnie HTTPS, zmieniając plik Web.config:

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

4 - Użyj pakietu NWebSec.Owin NuGet i dodaj następujący wiersz kodu, aby włączyć Strict Transport Security w całej witrynie. Nie zapomnij dodać dyrektywy Preload poniżej i przesłać swoją stronę do strony HSTS Preload . Więcej informacji tutaj i tutaj . Pamiętaj, że jeśli nie używasz OWIN, istnieje metoda Web.config, którą możesz przeczytać na stronie NWebSec .

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

5 - Użyj pakietu NWebSec.Owin NuGet i dodaj następujący wiersz kodu, aby włączyć przypinanie klucza publicznego (HPKP) w całej witrynie. Więcej informacji tutaj i tutaj .

// 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 - Uwzględnij schemat https we wszystkich używanych adresach URL. Nagłówek HTTP Content Security Policy (CSP) i integralność podrzędnych zasobów (SRI) nie działają dobrze, jeśli naśladujesz schemat w niektórych przeglądarkach. Lepiej jest wyraźnie powiedzieć o HTTPS. na przykład

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

Łatwa droga

Użyj szablonu projektu Visual Studio ASP.NET MVC Boilerplate, aby wygenerować projekt z tym wszystkim io wiele więcej wbudowanym. Możesz także wyświetlić kod w GitHub .

Muhammad Rehan Saeed
źródło
3
Również jeśli używasz <authentication mode="Forms">, w środku musisz mieć<forms requireSSL="true">
Pluto
1
@ muhammad-rehan-saeed Korzystam z płyty mvc5, ale strona nie przekierowuje automatycznie http na https na serwerze produkcyjnym, robi to, więc tylko na localhost jest coś, czego mi brakuje?
Diin
To nie jest właściwe forum do zadawania tego pytania. Opublikuj problem na stronie GitHub. RequireHttpsAttributeRobi przekierowanie. Tak długo, jak masz, powinno być dobrze.
Muhammad Rehan Saeed
@MuhammadRehanSaeed, uwielbiam twoją odpowiedź. Ale ... jak mogę uzyskać skrót SHA256 certyfikatu utworzonego za pomocą MakeCert? Wszystko, co mam, to odcisk palca SHA-1 ... Czy wiesz, że wiesz?
Diana
1
@Diana ten link może pokazać Ci, jak to zrobić.
Muhammad Rehan Saeed
13

Jeśli nie możesz tego ustawić w IIS z jakiegokolwiek powodu, stworzę moduł HTTP, który wykona dla ciebie przekierowanie:

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

Następnie po prostu skompiluj go do biblioteki DLL, dodaj jako odniesienie do swojego projektu i umieść to w pliku web.config:

 <httpModules>
      <add name="HttpsOnlyModule" type="HttpsOnly.HttpsOnlyModule, HttpsOnly" />
 </httpModules>
FlySwat
źródło
Wydaje się, że jest to bardziej zaangażowane niż zwykłe umieszczanie go na globalnej stronie. Osax - po prostu ciekawy, czy jest jakaś zaleta?
Brian MacKay
1
Zaletą byłoby, jeśli nie chcesz go używać, po prostu skomentuj moduł w pliku web.config. To rozwiązanie jest konfigurowalne, a drugie nie.
Bob Yexley,
2
Jestem trochę zdezorientowany. Spodziewałem się czegoś podobnego app.BeginRequest += new OnBeginRequest;w Initmetodzie i w OnBeginRequestzawierałoby to, co zawiera obecna Initmetoda. Czy na pewno ten moduł działa zgodnie z oczekiwaniami?
Jakub Šturc,
To nie działa. Musisz dodać zdarzenie OnBeginRequest itp., A następnie zadziała.
SnAzBaZ
Chciałbym edytować ten wadliwy kod, ale aby go zabezpieczyć, musisz również użyć HSTS. Po prostu skorzystaj z odpowiedzi Troy Hunt i uczyń z niego moduł; patrz support.microsoft.com/en-us/kb/307996 (staruszek, ale skarbie).
Marc L.
4

Co musisz zrobić, to:

1) Dodaj klucz do pliku web.config, w zależności od serwera produkcyjnego lub scenicznego, jak poniżej

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

2) Wewnątrz pliku Global.asax dodaj poniższą metodę.

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
źródło
3

Jeśli obsługa SSL nie jest konfigurowalna w Twojej witrynie (tzn. Powinna mieć możliwość włączenia / wyłączenia protokołu https) - możesz użyć atrybutu [RequireHttps] dla dowolnego działania kontrolera / kontrolera, który chcesz zabezpieczyć.

Yarg
źródło
2

Zależy to również od marki twojego modułu równoważącego, w przypadku multipleksera internetowego musisz poszukać nagłówka http, X-WebMux-SSL-termination: trueaby stwierdzić, że przychodzący ruch to ssl. szczegóły tutaj: http://www.cainetworks.com/support/redirect2ssl.html

Alexander
źródło
2

Dla @Joe powyżej: „Daje mi to pętlę przekierowania. Zanim dodałem kod, działał dobrze. Wszelkie sugestie? - Joe 8 listopada 11 'o ​​4:13”

To samo mi się przydarzyło i moim zdaniem działo się tak, że moduł równoważenia obciążenia zakończył żądanie SSL przed serwerem WWW. Tak więc moja witryna zawsze myślała, że ​​żądanie to „http”, nawet jeśli oryginalna przeglądarka zażądała, aby było to „https”.

Przyznaję, że jest to trochę zuchwałe, ale działało dla mnie wdrożenie właściwości „JustRedirected”, którą mogłem wykorzystać, aby dowiedzieć się, że osoba została już raz przekierowana. Testuję więc określone warunki, które uzasadniają przekierowanie, a jeśli są spełnione, ustawiam tę właściwość (wartość przechowywana w sesji) przed przekierowaniem. Nawet jeśli warunki http / https dla przekierowania zostaną spełnione po raz drugi, pomijam logikę przekierowania i resetuję wartość sesji „JustRedirected” na false. Będziesz potrzebował własnej logiki testu warunkowego, ale oto prosta implementacja właściwości:

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

            return (bool)Session[RosadaConst.JUSTREDIRECTED];
        }
        set
        {
            Session[RosadaConst.JUSTREDIRECTED] = value;
        }
    }
Paul Schroeder
źródło
2

Zamierzam wrzucić moje dwa centy. JEŻELI masz dostęp do strony serwera IIS, możesz wymusić HTTPS za pomocą powiązań protokołu. Na przykład masz witrynę internetową o nazwie Blah . W IIS skonfigurowałbyś dwie witryny: Blah i Blah (Przekierowanie) . W przypadku Bla skonfiguruj tylko HTTPSpowiązanie (a FTPjeśli to konieczne, pamiętaj, aby wymusić to również przez bezpieczne połączenie). W przypadku Blaha (przekierowanie) skonfiguruj tylko HTTPpowiązanie. Na koniec w sekcji Przekierowanie HTTP dla Blaha (Przekierowanie) upewnij się, że ustawiłeś przekierowanie 301 https://blah.com, z włączonym dokładnym miejscem docelowym. Upewnij się, że każda witryna w IIS wskazuje na towłasny folder główny, inaczej Web.config zostanie zepsuty. Upewnij się również, żeHSTS skonfigurowane w witrynie HTTPSed, tak aby kolejne żądania przeglądarki były zawsze wymuszane na HTTPS i nie dochodziło do przekierowań.

Gup3rSuR4c
źródło
2

To jest pełniejsza odpowiedź na podstawie @Troy Hunt's. Dodaj tę funkcję do swojej WebApplicationklasy w 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;
            }
        }
    }

(Aby włączyć protokół SSL w lokalnej kompilacji, włącz go w doku Właściwości dla projektu)

noelicus
źródło
1

-> Po prostu DODAJ [RequireHttps] na szczycie klasy HomeController: Kontroler.

-> I dodaj GlobalFilters.Filters.Add (new RequireHttpsAttribute ()); w metodzie „protected void Application_Start ()” w pliku Global.asax.cs.

Co wymusza całą aplikację do HTTPS.

Santosh K.
źródło
Nie wierzę, że to zadziała dla wszystkich stron obsługiwanych przy użyciu WebForms lub jakichkolwiek interfejsów API zbudowanych z WebAPI. Dotyczy to tylko kontrolerów MVC.
Marc L.
1

Spędziłem trochę czasu na poszukiwaniu najlepszych praktyk, które mają sens i znalazłem następujące, które działały dla mnie perfekcyjnie. Mam nadzieję, że to cię kiedyś uratuje.

Za pomocą pliku Config (na przykład strona asp.net) https://blogs.msdn.microsoft.com/kaushal/2013/05/22/http-to-https-redirects-on-iis-7-x-and- wyższy/

lub na własnym serwerze https://www.sslshopper.com/iis7-redirect-http-to-https.html

[KRÓTKA ODPOWIEDŹ] Po prostu poniższy kod wchodzi do środka

<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
źródło
1

W IIS10 (Windows 10 i Server 2016), począwszy od wersji 1709, dostępna jest nowa, prostsza opcja włączania HSTS dla strony internetowej.

Microsoft opisać zalety nowego podejścia tutaj i zapewniają wiele różnych przykładów, jak wdrożyć zmiany programowo lub przez bezpośrednią edycję pliku ApplicationHost.config (co jest jak web.config ale działa na IIS poziom, zamiast indywidualnego poziomie zakładu ). ApplicationHost.config można znaleźć w C: \ Windows \ System32 \ inetsrv \ config.

Przedstawiłem tutaj dwie przykładowe metody, aby uniknąć gnicia linków.

Metoda 1 - Edytuj plik ApplicationHost.config bezpośrednio Między <site>znacznikami dodaj następujący wiersz:

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

Metoda 2 - Wiersz poleceń: Wykonaj następujące czynności z wiersza polecenia z podwyższonym poziomem uprawnień (tj. Prawą myszą na CMD i uruchom jako administrator). Pamiętaj, aby zamienić Contoso na nazwę swojej strony, która pojawia się w Menedżerze 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

Inne metody oferowane przez Microsoft w tych artykułach mogą być lepszymi opcjami, jeśli korzystasz z hostowanego środowiska, w którym masz ograniczony dostęp.

Należy pamiętać, że IIS10 wersja 1709 jest teraz dostępna w systemie Windows 10, ale w przypadku systemu Windows Server 2016 jest na innej ścieżce wydania i nie zostanie wydana jako poprawka lub dodatek Service Pack. Zobacz tutaj szczegóły na temat 1709.

Mikrofon
źródło
0

Jeśli używasz programu ASP.NET Core, możesz wypróbować pakiet nuget SaidOut.AspNetCore.HttpsWithStrictTransportSecurity.

Musisz tylko dodać

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

Spowoduje to również dodanie nagłówka HTTP StrictTransportSecurity do wszystkich żądań złożonych przy użyciu schematu https.

Przykładowy kod i dokumentacja https://github.com/saidout/saidout-aspnetcore-httpswithstricttransportsecurity#example-code

użytkownik7755300
źródło