Pages SSL sous ASP.NET MVC

Comment puis-je utiliser HTTPS pour certaines des pages de mon site ASP.NET MVC?

Steve Sanderson a un très bon tutoriel sur la façon de le faire de façon SEC sur Preview 4 à:

http://blog.codeville.net/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/

Existe-t-il un moyen meilleur / mis à jour avec Preview 5?

Si vous utilisez ASP.NET MVC 2 Preview 2 ou supérieur , vous pouvez maintenant utiliser simplement:

[RequireHttps] public ActionResult Login() { return View(); } 

Cependant, le paramètre de commande est à noter, comme mentionné ici .

MVCFutures a un atsortingbut ‘RequireSSL’.

(merci Adam de l’avoir souligné dans votre blogpost mis à jour)

Appliquez-le simplement à votre méthode d’action, avec «Redirect = true» si vous voulez qu’une requête http: // devienne automatiquement https: //:

  [RequireSsl(Redirect = true)] 

Voir aussi: ASP.NET MVC RequireHttps en production uniquement

Comme Amadiere l’a écrit , [RequireHttps] fonctionne parfaitement dans MVC 2 pour entrer dans HTTPS. Mais si vous souhaitez uniquement utiliser HTTPS pour certaines pages, comme vous l’avez dit, MVC 2 n’a pas d’amour – une fois qu’un utilisateur passe à HTTPS, il rest bloqué jusqu’à ce que vous le redirigiez manuellement.

L’approche que j’ai utilisée consiste à utiliser un autre atsortingbut personnalisé, [ExitHttpsIfNotRequired]. Une fois attaché à un contrôleur ou à une action, ceci redirecta vers HTTP si:

  1. La demande était HTTPS
  2. L’atsortingbut [RequireHttps] n’a pas été appliqué à l’action (ou au contrôleur)
  3. La demande était un GET (redirect un POST entraînerait toutes sortes de problèmes).

C’est un peu trop gros pour poster ici, mais vous pouvez voir le code ici et quelques détails supplémentaires.

Voici un article récent de Dan Wahlin à ce sujet:

http://weblogs.asp.net/dwahlin/archive/2009/08/25/requiring-ssl-for-asp-net-mvc-controllers.aspx

Il utilise un atsortingbut ActionFilter.

Certaines extensions ActionLink: http://www.squaredroot.com/post/2008/06/11/MVC-and-SSL.aspx Ou un atsortingbut d’action de contrôleur qui redirige vers https: // http://forums.asp.net /p/1260198/2358380.aspx#2358380

Pour ceux qui n’apprécient pas les approches de développement axées sur les atsortingbuts, voici un morceau de code qui pourrait vous aider:

 public static readonly ssortingng[] SecurePages = new[] { "login", "join" }; protected void Application_AuthorizeRequest(object sender, EventArgs e) { var pageName = RequestHelper.GetPageNameOrDefault(); if (!HttpContext.Current.Request.IsSecureConnection && (HttpContext.Current.Request.IsAuthenticated || SecurePages.Contains(pageName))) { Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"] + HttpContext.Current.Request.RawUrl); } if (HttpContext.Current.Request.IsSecureConnection && !HttpContext.Current.Request.IsAuthenticated && !SecurePages.Contains(pageName)) { Response.Redirect("http://" + Request.ServerVariables["HTTP_HOST"] + HttpContext.Current.Request.RawUrl); } } 

Il y a plusieurs raisons pour éviter les atsortingbuts et l’un d’entre eux est que si vous voulez regarder la liste de toutes les pages sécurisées, vous devrez passer par-dessus tous les contrôleurs en solution.

J’ai rencontré cette question et j’espère que ma solution peut aider quelqu’un.

Nous avons eu quelques problèmes: – Nous devons sécuriser des actions spécifiques, par exemple “LogOn” dans “Compte”. Nous pouvons utiliser l’atsortingbut RequireHttps, ce qui est bien, mais cela nous redirecta avec https: //. – Nous devrions faire nos liens, formulaires et autres “SSL aware”.

En général, ma solution permet de spécifier des routes qui utiliseront une URL absolue, en plus de la possibilité de spécifier le protocole. Vous pouvez utiliser cette approche pour spécifier le protocole “https”.

Donc, premièrement, j’ai créé une énumération ConnectionProtocol:

 ///  /// Enum representing the available secure connection requirements ///  public enum ConnectionProtocol { ///  /// No secure connection requirement ///  Ignore, ///  /// No secure connection should be used, use standard http request. ///  Http, ///  /// The connection should be secured using SSL (https protocol). ///  Https } 

Maintenant, j’ai créé une version roulée à la main de RequireSsl. J’ai modifié le code source RequireSsl d’origine pour autoriser la redirection vers les URL http: //. De plus, j’ai mis un champ qui nous permet de déterminer si nous avons besoin de SSL ou non (je l’utilise avec le préprocesseur DEBUG).

 /* Note: * This is hand-rolled version of the original System.Web.Mvc.RequireHttpsAtsortingbute. * This version contains three improvements: * - Allows to redirect back into http:// addresses, based on the  Requirement property. * - Allows to turn the protocol scheme redirection off based on given condition. * - Using Request.IsCurrentConnectionSecured() extension method, which contains fix for load-balanced servers. */ [AtsortingbuteUsage(AtsortingbuteTargets.Class | AtsortingbuteTargets.Method, Inherited = true, AllowMultiple = false)] public sealed class RequireHttpsAtsortingbute : FilterAtsortingbute, IAuthorizationFilter { public RequireHttpsAtsortingbute() { Protocol = ConnectionProtocol.Ignore; } ///  /// Gets or sets the secure connection required protocol scheme level ///  public ConnectionProtocol Protocol { get; set; } ///  /// Gets the value that indicates if secure connections are been allowed ///  public bool SecureConnectionsAllowed { get { #if DEBUG return false; #else return true; #endif } } public void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } /* Are we allowed to use secure connections? */ if (!SecureConnectionsAllowed) return; switch (Protocol) { case ConnectionProtocol.Https: if (!filterContext.HttpContext.Request.IsCurrentConnectionSecured()) { HandleNonHttpsRequest(filterContext); } break; case ConnectionProtocol.Http: if (filterContext.HttpContext.Request.IsCurrentConnectionSecured()) { HandleNonHttpRequest(filterContext); } break; } } private void HandleNonHttpsRequest(AuthorizationContext filterContext) { // only redirect for GET requests, otherwise the browser might not propagate the verb and request // body correctly. if (!Ssortingng.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", SsortingngComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("The requested resource can only be accessed via SSL."); } // redirect to HTTPS version of page ssortingng url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; filterContext.Result = new RedirectResult(url); } private void HandleNonHttpRequest(AuthorizationContext filterContext) { if (!Ssortingng.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", SsortingngComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("The requested resource can only be accessed without SSL."); } // redirect to HTTP version of page ssortingng url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; filterContext.Result = new RedirectResult(url); } } 

Maintenant, cette RequireSsl fera la base suivante sur la valeur de votre atsortingbut Requirements: – Ignorer: Ne rien faire. – Http: forcera la redirection vers le protocole http. – Https: forcera la redirection vers le protocole https.

Vous devez créer votre propre contrôleur de base et définir cet atsortingbut sur HTTP.

 [RequireSsl(Requirement = ConnectionProtocol.Http)] public class MyController : Controller { public MyController() { } } 

Maintenant, dans chaque action / cpntroller que vous souhaitez exiger SSL – il suffit de définir cet atsortingbut avec ConnectionProtocol.Https.

Passons maintenant aux URL: nous avons eu quelques problèmes avec le moteur de routage des URL. Vous pouvez en savoir plus à leur sujet sur http://blog.stevensanderson.com/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/ . La solution proposée dans cet article est théoriquement bonne, mais ancienne et je n’aime pas cette approche.

Mes solutions sont les suivantes: Créez une sous-classe de la classe de base “Route”:

Classe publique AbsoluteUrlRoute: Route {#region ctor

  ///  /// Initializes a new instance of the System.Web.Routing.Route class, by using /// the specified URL pattern and handler class. ///  /// The URL pattern for the route. /// The object that processes requests for the route. public AbsoluteUrlRoute(ssortingng url, IRouteHandler routeHandler) : base(url, routeHandler) { } ///  /// Initializes a new instance of the System.Web.Routing.Route class, by using /// the specified URL pattern and handler class. ///  /// The URL pattern for the route. /// The values to use for any parameters that are missing in the URL. /// The object that processes requests for the route. public AbsoluteUrlRoute(ssortingng url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler) { } ///  /// Initializes a new instance of the System.Web.Routing.Route class, by using /// the specified URL pattern and handler class. ///  /// The URL pattern for the route. /// The values to use for any parameters that are missing in the URL. /// A regular expression that specifies valid values for a URL parameter. /// The object that processes requests for the route. public AbsoluteUrlRoute(ssortingng url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler) : base(url, defaults, constraints, routeHandler) { } ///  /// Initializes a new instance of the System.Web.Routing.Route class, by using /// the specified URL pattern and handler class. ///  /// The URL pattern for the route. /// The values to use for any parameters that are missing in the URL. /// A regular expression that specifies valid values for a URL parameter. /// Custom values that are passed to the route handler, but which are not used /// to determine whether the route matches a specific URL pattern. These values /// are passed to the route handler, where they can be used for processing the /// request. /// The object that processes requests for the route. public AbsoluteUrlRoute(ssortingng url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler) : base(url, defaults, constraints, dataTokens, routeHandler) { } #endregion public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { var virtualPath = base.GetVirtualPath(requestContext, values); if (virtualPath != null) { var scheme = "http"; if (this.DataTokens != null && (ssortingng)this.DataTokens["scheme"] != ssortingng.Empty) { scheme = (ssortingng) this.DataTokens["scheme"]; } virtualPath.VirtualPath = MakeAbsoluteUrl(requestContext, virtualPath.VirtualPath, scheme); return virtualPath; } return null; } #region Helpers ///  /// Creates an absolute url ///  /// The request context /// The initial virtual relative path /// The protocol scheme /// The absolute URL private ssortingng MakeAbsoluteUrl(RequestContext requestContext, ssortingng virtualPath, ssortingng scheme) { return ssortingng.Format("{0}://{1}{2}{3}{4}", scheme, requestContext.HttpContext.Request.Url.Host, requestContext.HttpContext.Request.ApplicationPath, requestContext.HttpContext.Request.ApplicationPath.EndsWith("/") ? "" : "/", virtualPath); } #endregion } 

Cette version de la classe “Route” créera une URL absolue. L’astuce ici, suivie de la suggestion de l’auteur de l’article sur le blog, consiste à utiliser le DataToken pour spécifier le schéma (exemple à la fin :)).

Maintenant, si nous générons une URL, par exemple pour la route “Account / LogOn”, nous aurons “/ http://example.com/Account/LogOn ” – puisque UrlRoutingModule voit toutes les URL comme relatives. Nous pouvons résoudre ce problème en utilisant un HttpModule personnalisé:

 public class AbsoluteUrlRoutingModule : UrlRoutingModule { protected override void Init(System.Web.HttpApplication application) { application.PostMapRequestHandler += application_PostMapRequestHandler; base.Init(application); } protected void application_PostMapRequestHandler(object sender, EventArgs e) { var wrapper = new AbsoluteUrlAwareHttpContextWrapper(((HttpApplication)sender).Context); } public override void PostResolveRequestCache(HttpContextBase context) { base.PostResolveRequestCache(new AbsoluteUrlAwareHttpContextWrapper(HttpContext.Current)); } private class AbsoluteUrlAwareHttpContextWrapper : HttpContextWrapper { private readonly HttpContext _context; private HttpResponseBase _response = null; public AbsoluteUrlAwareHttpContextWrapper(HttpContext context) : base(context) { this._context = context; } public override HttpResponseBase Response { get { return _response ?? (_response = new AbsoluteUrlAwareHttpResponseWrapper(_context.Response)); } } private class AbsoluteUrlAwareHttpResponseWrapper : HttpResponseWrapper { public AbsoluteUrlAwareHttpResponseWrapper(HttpResponse response) : base(response) { } public override ssortingng ApplyAppPathModifier(ssortingng virtualPath) { int length = virtualPath.Length; if (length > 7 && virtualPath.Subssortingng(0, 7) == "/http:/") return virtualPath.Subssortingng(1); else if (length > 8 && virtualPath.Subssortingng(0, 8) == "/https:/") return virtualPath.Subssortingng(1); return base.ApplyAppPathModifier(virtualPath); } } } } 

Étant donné que ce module remplace l’implémentation de base de UrlRoutingModule, nous devrions supprimer la base httpModule et enregistrer les nôtres dans web.config. Donc, sous “system.web”, définissez:

      

C’est tout :).

Pour enregistrer un itinéraire suivi absolu / protocole, vous devez faire:

  routes.Add(new AbsoluteUrlRoute("Account/LogOn", new MvcRouteHandler()) { Defaults = new RouteValueDictionary(new {controller = "Account", action = "LogOn", area = ""}), DataTokens = new RouteValueDictionary(new {scheme = "https"}) }); 

Aime entendre vos commentaires et améliorations. J’espère que ça peut aider! 🙂

Edit: J’ai oublié d’inclure la méthode d’extension IsCurrentConnectionSecured () (trop de snippets: P). C’est une méthode d’extension qui utilise généralement Request.IsSecuredConnection. Cependant, cette approche ne fonctionnera pas lors de l’utilisation de l’équilibrage de charge – cette méthode peut donc être contournée (prise depuis nopCommerce).

  ///  /// Gets a value indicating whether current connection is secured ///  /// The base request context /// true - secured, false - not secured /// nopCommerce WebHelper IsCurrentConnectionSecured()]]> public static bool IsCurrentConnectionSecured(this HttpRequestBase request) { return request != null && request.IsSecureConnection; // when your hosting uses a load balancer on their server then the Request.IsSecureConnection is never got set to true, use the statement below // just uncomment it //return request != null && request.ServerVariables["HTTP_CLUSTER_HTTPS"] == "on"; } 

Voici un article de janvier 2009 de Pablo M. Cibrano qui rassemble quelques techniques, dont un HttpModule et des méthodes d’extension.

Voici un article de Adam Salvo qui utilise un ActionFilter.

Ce n’est pas nécessairement spécifique à MVC, mais cette solution fonctionne à la fois pour ASP.NET WebForms et MVC:

http://www.codeproject.com/KB/web-security/WebPageSecurity_v2.aspx

Je l’utilise depuis plusieurs années et aime la séparation des préoccupations et de la gestion via le fichier web.config.

MVC 6 (ASP.NET Core 1.0) fonctionne légèrement avec Startup.cs.

Pour utiliser RequireHttpsAtsortingbute (comme mentionné dans la réponse par Amadiere) sur toutes les pages, vous pouvez append ceci dans Startup.cs au lieu d’utiliser un style d’atsortingbut sur chaque contrôleur (ou plutôt de créer un BaseController pour tous vos contrôleurs).

Startup.cs – Filtre de registre:

 public void ConfigureServices(IServiceCollection services) { // TODO: Register other services services.AddMvc(options => { options.Filters.Add(typeof(RequireHttpsAtsortingbute)); }); } 

Pour plus d’informations sur les décisions de conception pour l’approche ci-dessus, consultez ma réponse à une question similaire sur la façon d’exclure les requêtes localhost de la gestion de RequireHttpsAtsortingbute .