Le meilleur moyen dans asp.net de forcer https pour un site entier?

193

Il y a environ 6 mois, j'ai déployé un site où chaque demande devait être sur https. Le seul moyen à l'époque que je pouvais trouver pour m'assurer que chaque demande à une page était sur https était de le vérifier dans l'événement de chargement de page. Si la demande n'était pas terminée sur http, je répondrais.redirect (" https://example.com ")

Y a-t-il un meilleur moyen - idéalement un paramètre dans le web.config?

codétrift
la source
vérifiez ma réponse ici stackoverflow.com/questions/33882350/…
Shady Sherif

Réponses:

251

Veuillez utiliser HSTS (HTTP Strict Transport Security)

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

Réponse originale (remplacée par ce qui précède le 4 décembre 2015)

fondamentalement

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

qui irait dans le global.asax.cs (ou global.asax.vb)

je ne connais pas de moyen de le spécifier dans le web.config

John Boker
la source
7
Cela fonctionne, mais c'était dangereux pour moi: quand j'ai essayé de s'exécuter localement dans VS 2010 avec ce code en cours d'exécution, ma page de démarrage ne s'est jamais chargée; à la place, je viens de recevoir un message "Cette page Web n'est pas disponible". Pour corriger, j'ai ajouté une deuxième condition pour tester si l'url contient la chaîne "localhost": si ce n'est pas le cas, forcez https.
mg1075
3
Cela me donne une boucle de redirection. Avant d'ajouter le code, cela fonctionnait bien. Aucune suggestion?
Joe
9
Veuillez noter que cela ne fournit aucune sécurité utile. En fait, il ne sécurisera que les connexions des utilisateurs déjà sûrs, et échouera à sécuriser ceux qui sont attaqués (c'est parce qu'un MITM peut simplement omettre complètement la redirection et transmettre tout à votre site "sécurisé"). À mon humble avis, la redirection des agents utilisateurs est juste une sécurité vaudou de bien-être et fournit une illusion parfois dangereuse de sécurité. La seule façon de procéder est de demander aux agents utilisateurs de ne demander que des ressources sécurisées, et non de les rediriger s'ils ne le font pas. C'est ce que fait HSTS - voir les réponses ci-dessous.
tne
2
Cette réponse doit être considérée comme «nuisible» et ne doit pas être utilisée. Selon le commentaire de @tne ci-dessus.
Rosdi Kasim
2
@RosdiKasim Cette réponse devrait-elle toujours être considérée comme nuisible depuis l'édition du 4 décembre 15?
Andrew Morton
123

L'autre chose que vous pouvez faire est d'utiliser HSTS en renvoyant l'en-tête "Strict-Transport-Security" au navigateur. Le navigateur doit prendre en charge cela (et à l'heure actuelle, ce sont principalement Chrome et Firefox qui le font), mais cela signifie qu'une fois défini, le navigateur ne fera pas de requêtes au site via HTTP et les traduira à la place en requêtes HTTPS avant de les émettre. . Essayez ceci en combinaison avec une redirection de 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;
  }
}

Les navigateurs qui ne sont pas conscients de HSTS ignoreront simplement l'en-tête mais seront toujours capturés par l'instruction switch et envoyés à HTTPS.

Chasse à Troie
la source
6
Jamais entendu parler de l'en-tête HSTS auparavant, mais il a l'air plutôt cool. Y a-t-il une raison d'utiliser une si petite valeur d'âge maximum (5 minutes)? L'article Wikipédia vers lequel vous créez un lien suggère de le définir sur une valeur élevée (6 à 12 mois).
dana
5
+1. Consultez cet article très complet sur le blog de Troy qui comprend des détails sur les raisons pour lesquelles seule l'utilisation de redirections peut réduire la sécurité. Astuce: cela peut vous rendre vulnérable à l'outil SSL Strip, entre autres. troyhunt.com/2011/11/…
Oran Dennison
3
Il vaut également la peine de vérifier NWebsec , ce qui rend cela (et plus) très facile.
Tieson T.
16
Vous voudrez envelopper le commutateur if(!Request.IsLocal)afin qu'il n'interrompe pas le débogage.
Justin J Stark
1
Bonne réponse. Une subtilité - Pour les en-têtes Http ("Strict-Transport-Security"), il est préférable d'utiliser une bibliothèque comme NWebSec car il existe plusieurs options qui sont concentrées dans un seul endroit de configuration plutôt que réparties ici et là.
Ognyan Dimitrov
89

Le module IIS7 vous permettra de rediriger.

    <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>
marque
la source
12
De plus, pour IIS 7.0, vous devez installer le module de réécriture d'url 2.0
Chris
J'ai trouvé ce lien simple et utile pour faire en sorte qu'une page particulière n'accepte que les demandes https - support.microsoft.com/kb/239875
Manik Arora
21

Pour ceux qui utilisent ASP.NET MVC. Vous pouvez utiliser ce qui suit pour forcer SSL / TLS sur HTTPS sur l'ensemble du site de deux manières:

À la dure

1 - Ajoutez le RequireHttpsAttribute aux filtres globaux:

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

2 - Forcer les jetons Anti-Forgery à utiliser SSL / TLS:

AntiForgeryConfig.RequireSsl = true;

3 - Exiger que les cookies requièrent HTTPS par défaut en modifiant le fichier Web.config:

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

4 - Utilisez le package NuGet NWebSec.Owin et ajoutez la ligne de code suivante pour activer Strict Transport Security sur le site. N'oubliez pas d'ajouter la directive Preload ci-dessous et soumettez votre site au site HSTS Preload . Plus d'informations ici et ici . Notez que si vous n'utilisez pas OWIN, il existe une méthode Web.config que vous pouvez consulter sur le site NWebSec .

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

5 - Utilisez le package NuGet NWebSec.Owin et ajoutez la ligne de code suivante pour activer l'épinglage par clé publique (HPKP) sur le site. Plus d'informations ici et ici .

// 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 - Incluez le schéma https dans toutes les URL utilisées. L' en-tête HTTP de la politique de sécurité du contenu (CSP) et l' intégrité des sous-ressources (SRI) ne fonctionnent pas bien lorsque vous imitez le schéma dans certains navigateurs. Il vaut mieux être explicite sur HTTPS. par exemple

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

La manière facile

Utilisez le modèle de projet ASP.NET MVC Boilerplate Visual Studio pour générer un projet avec tout cela et bien plus encore intégré. Vous pouvez également afficher le code sur GitHub .

Muhammad Rehan Saeed
la source
3
Aussi si vous utilisez <authentication mode="Forms">, à l'intérieur, vous devez avoir<forms requireSSL="true">
Pluto
1
@ muhammad-rehan-saeed J'utilise mvc5 passe-partout mais le site ne redirige pas automatiquement http vers https sur le serveur de production, il ne le fait que sur localhost, y a-t-il quelque chose qui me manque?
Diin
Ce n'est pas le bon forum pour poser cette question. Publiez un problème sur le site GitHub. Le RequireHttpsAttributefait la redirection. Tant que vous l'avez, ça devrait aller.
Muhammad Rehan Saeed
@MuhammadRehanSaeed, adore ta réponse. Mais ... comment obtenir le hachage SHA256 d'un certificat créé avec MakeCert? Tout ce que j'ai, c'est une empreinte numérique SHA-1 ... Le savez-vous?
Diana
1
@Diana ce lien peut vous montrer comment.
Muhammad Rehan Saeed
13

Si vous ne parvenez pas à configurer cela dans IIS pour une raison quelconque, je créerais un module HTTP qui effectue la redirection pour vous:

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

Ensuite, compilez-le simplement dans une DLL, ajoutez-le comme référence à votre projet et placez-le dans web.config:

 <httpModules>
      <add name="HttpsOnlyModule" type="HttpsOnly.HttpsOnlyModule, HttpsOnly" />
 </httpModules>
FlySwat
la source
Cela semble plus complexe que de simplement le coller dans le global.asax - juste curieux, y a-t-il un avantage?
Brian MacKay
1
L'avantage serait que, lorsque vous ne voulez pas l'utiliser, il suffit de commenter le module dans votre web.config. Cette solution est configurable, tandis que l'autre ne l'est pas.
Bob Yexley
2
Je suis un peu confus. Je m'attendais à quelque chose comme app.BeginRequest += new OnBeginRequest;dans la Initméthode et dans le OnBeginRequestcontiendrait ce que contient la Initméthode actuelle . Êtes-vous sûr que ce module fonctionne comme prévu?
Jakub Šturc
Ça ne marche pas. Vous devez ajouter l'événement OnBeginRequest, etc., puis cela fonctionne.
SnAzBaZ
Je modifierais ce code défectueux, mais pour le rendre sécurisé, vous devez également utiliser HSTS. Allez simplement avec la réponse de Troy Hunt et faites-en un module; voir support.microsoft.com/en-us/kb/307996 (un oldie, mais goodie).
Marc L.
4

Ce que vous devez faire est:

1) Ajoutez une clé à l'intérieur de web.config, en fonction du serveur de production ou de scène comme ci-dessous

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

2) Dans votre fichier Global.asax, ajoutez la méthode ci-dessous.

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
la source
3

Si le support SSL n'est pas configurable dans votre site (par exemple, devrait pouvoir activer / désactiver https) - vous pouvez utiliser l'attribut [RequireHttps] sur toute action de contrôleur / contrôleur que vous souhaitez sécuriser.

yarg
la source
2

Cela dépend également de la marque de votre équilibreur, pour le multiplexeur Web, vous devrez rechercher l'en-tête http X-WebMux-SSL-termination: truepour déterminer que le trafic entrant était SSL. détails ici: http://www.cainetworks.com/support/redirect2ssl.html

Alexandre
la source
2

Pour @Joe ci-dessus, "Cela me donne une boucle de redirection. Avant d'ajouter le code, cela fonctionnait bien. Des suggestions? - Joe 8 novembre 11 à 4:13"

Cela m'arrivait également et je crois qu'il se passait un équilibreur de charge mettant fin à la requête SSL devant le serveur Web. Ainsi, mon site Web pensait toujours que la requête était "http", même si le navigateur d'origine demandait qu'elle soit "https".

J'admets que c'est un peu piraté, mais ce qui a fonctionné pour moi était d'implémenter une propriété "JustRedirected" que je pourrais utiliser pour comprendre que la personne a déjà été redirigée une fois. Donc, je teste les conditions spécifiques qui justifient la redirection et, si elles sont remplies, je règle cette propriété (valeur stockée en session) avant la redirection. Même si les conditions http / https pour la redirection sont remplies la deuxième fois, je contourne la logique de redirection et réinitialise la valeur de session «JustRedirected» sur false. Vous aurez besoin de votre propre logique de test conditionnel, mais voici une implémentation simple de la propriété:

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

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

Je vais jeter mes deux cents dedans. SI vous avez accès au côté serveur IIS, alors vous pouvez forcer HTTPS en utilisant les liaisons de protocole. Par exemple, vous avez un site Web appelé Blah . Dans IIS, vous configurez deux sites: Blah et Blah (Redirection) . Pour Blah, configurez uniquement la HTTPSliaison (et FTPsi vous en avez besoin, assurez-vous également de la forcer via une connexion sécurisée). Pour Blah (Redirection), configurez uniquement la HTTPliaison. Enfin, dans la section HTTP Redirect pour Blah (Redirect), assurez-vous de définir une redirection 301 vers votre propre dossier racine, sinon le Web.confighttps://blah.com , avec la destination exacte activée. Assurez-vous que chaque site dans IIS pointe vers sera tout foutu. Assurez-vous également d'avoir HSTSconfiguré sur votre site HTTPSed afin que les demandes ultérieures du navigateur soient toujours forcées à HTTPS et qu'aucune redirection ne se produise.

Gup3rSuR4c
la source
2

Ceci est une réponse plus complète basée sur @Troy Hunt. Ajoutez cette fonction à votre WebApplicationclasse dans 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;
            }
        }
    }

(Pour activer SSL sur votre build local, activez-le dans le dock Propriétés du projet)

noelicus
la source
1

-> Ajoutez simplement [RequireHttps] en haut de la classe publique HomeController: Controller.

-> Et ajoutez GlobalFilters.Filters.Add (nouveau RequireHttpsAttribute ()); dans la méthode 'protected void Application_Start ()' dans le fichier Global.asax.cs.

Ce qui oblige l'ensemble de votre application à passer au HTTPS.

Santosh K
la source
Je ne pense pas que cela fonctionnera pour les pages servies à l'aide de WebForms ou de toute API construite avec WebAPI. Il ne couvrira que les contrôleurs MVC.
Marc L.
1

J'ai passé du temps à chercher les meilleures pratiques qui ont du sens et j'ai trouvé les suivantes qui fonctionnaient parfaitement pour moi. J'espère que cela vous sauvera un jour.

Utilisation du fichier de configuration (par exemple un site Web asp.net) https://blogs.msdn.microsoft.com/kaushal/2013/05/22/http-to-https-redirects-on-iis-7-x-and- plus haute/

ou sur votre propre serveur https://www.sslshopper.com/iis7-redirect-http-to-https.html

[RÉPONSE COURTE] Simplement Le code ci-dessous entre à l'intérieur

<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
la source
1

Dans IIS10 (Windows 10 et Server 2016), à partir de la version 1709, il existe une nouvelle option plus simple pour activer HSTS pour un site Web.

Microsoft décrit les avantages de la nouvelle approche ici , et de fournir de nombreux exemples de la façon de mettre en œuvre le changement d'un programme ou en modifiant directement le fichier ApplicationHost.config (qui est comme web.config mais fonctionne au niveau IIS, plutôt qu'au niveau de chaque site ). ApplicationHost.config se trouve dans C: \ Windows \ System32 \ inetsrv \ config.

J'ai décrit ici deux des méthodes d'exemple pour éviter la pourriture des liens.

Méthode 1 - Modifiez le fichier ApplicationHost.config directement Entre les <site>balises, ajoutez cette ligne:

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

Méthode 2 - Ligne de commande: exécutez ce qui suit à partir d'une invite de commande élevée (c'est-à-dire avec le bouton droit de la souris sur CMD et exécutez en tant qu'administrateur). N'oubliez pas d'échanger Contoso avec le nom de votre site tel qu'il apparaît dans le Gestionnaire des services Internet (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

Les autres méthodes proposées par Microsoft dans ces articles peuvent être de meilleures options si vous vous trouvez dans un environnement hébergé où vous avez un accès limité.

Gardez à l'esprit que la version 1709 d'IIS10 est maintenant disponible sur Windows 10, mais pour Windows Server 2016, il est sur une autre voie de publication et ne sera pas publié en tant que correctif ou service pack. Voir ici pour plus de détails sur 1709.

Mike
la source
0

Si vous utilisez ASP.NET Core, vous pouvez essayer le package nuget SaidOut.AspNetCore.HttpsWithStrictTransportSecurity.

Ensuite, il vous suffit d'ajouter

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

Cela ajoutera également l'en-tête HTTP StrictTransportSecurity à toutes les demandes effectuées à l'aide du schéma https.

Exemple de code et de documentation https://github.com/saidout/saidout-aspnetcore-httpswithstricttransportsecurity#example-code

user7755300
la source