ASP.NET MVC vereist alleen HTTPS in productie

Ik wil de gebruiken RequireHttpsAttributeom te voorkomen dat onbeveiligde HTTP-verzoeken naar een actiemethode worden verzonden.

C#

[RequireHttps] //apply to all actions in controller
public class SomeController 
{
    [RequireHttps] //apply to this action only
    public ActionResult SomeAction()
    {
        ...
    }
}

VB

<RequireHttps()> _
Public Class SomeController
    <RequireHttps()> _
    Public Function SomeAction() As ActionResult
        ...
    End Function
End Class

Helaas ondersteunt ASP.NET Development Server geen HTTPS.

Hoe kan ik ervoor zorgen dat mijn ASP.NET MVC-toepassing RequireHttps gebruikt wanneer deze wordt gepubliceerd in de productieomgeving, maar niet wanneer deze wordt uitgevoerd op mijn ontwikkelwerkstation op de ASP.NET Development Server?


Antwoord 1, autoriteit 100%

Dit helpt niet als u Release-builds uitvoert op uw ontwikkelwerkstation, maar voorwaardelijke compilatie zou het werk kunnen doen…

#if !DEBUG
[RequireHttps] //apply to all actions in controller
#endif
public class SomeController 
{
    //... or ...
#if !DEBUG
    [RequireHttps] //apply to this action only
#endif
    public ActionResult SomeAction()
    {
    }
}

Bijwerken

In Visual Basic maken attributen technisch gezien deel uit van dezelfde regel als de definitie waarop ze van toepassing zijn. Je kunt geen voorwaardelijke compilatie-instructies in een regel plaatsen, dus je bent gedwongen om de functiedeclaratie twee keer te schrijven – één keer met het attribuut en één keer zonder. Het werkt echter wel, als je de lelijkheid niet erg vindt.

#If Not Debug Then
    <RequireHttps()> _
    Function SomeAction() As ActionResult
#Else
    Function SomeAction() As ActionResult
#End If
        ...
    End Function

Update 2

Verschillende mensen hebben gezegd dat ze afkomstig zijn van RequireHttpsAttributezonder een voorbeeld te geven, dus hier is er een voor jou. Ik denk dat deze benadering veel schoner zou zijn dan de voorwaardelijke compilatiebenadering, en in jouw positie zou dit mijn voorkeur hebben.

DISCLAIMER: ik heb deze code niet getest, zelfs niet een klein beetje, en mijn VB is behoorlijk roestig. Ik weet alleen dat het compileert. Ik schreef het op basis van de suggesties van spot, queen3 en Lance Fisher. Als het niet werkt, moet het op zijn minst het algemene idee overbrengen en je een startpunt geven.

Public Class RemoteRequireHttpsAttribute
    Inherits System.Web.Mvc.RequireHttpsAttribute
    Public Overrides Sub OnAuthorization(ByVal filterContext As  _
                                         System.Web.Mvc.AuthorizationContext)
        If IsNothing(filterContext) Then
            Throw New ArgumentNullException("filterContext")
        End If
        If Not IsNothing(filterContext.HttpContext) AndAlso _
            filterContext.HttpContext.Request.IsLocal Then
            Return
        End If
        MyBase.OnAuthorization(filterContext)
    End Sub
End Class

Kortom, het nieuwe attribuut wordt gewoon afgesloten in plaats van de standaard SSL-autorisatiecode uit te voeren, als het huidige verzoek lokaal is (dat wil zeggen, je bent toegang tot de site via localhost). Je kunt het als volgt gebruiken:

<RemoteRequireHttps()> _
Public Class SomeController
    <RemoteRequireHttps()> _
    Public Function SomeAction() As ActionResult
        ...
    End Function
End Class

Veel schoner! Op voorwaarde dat mijn niet-geteste code echt werkt.


Antwoord 2, autoriteit 50%

Als iemand de C#-versie nodig heeft:

using System;
using System.Web.Mvc;
namespace My.Utils
{
    public class MyRequireHttpsAttribute : RequireHttpsAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            if (filterContext.HttpContext != null && filterContext.HttpContext.Request.IsLocal)
            {
                return;
            }
            base.OnAuthorization(filterContext);
        }
    }
}

3, Autoriteit 20%

Afkomst van eisenhtps is een goede aanpak.

Aan de zijkant de kwestie volledig, u kunt IIS op uw lokale computer gebruiken met een zelfondertekend certificaat ook. IIS is sneller dan de ingebouwde webserver en u hebt het voordeel dat uw ontwikkelingsomgeving meer op productie is.

Scott Hanselman heeft een geweldige bron op een paar manieren om lokale HTTPS te implementeren met VS2010 en IIS Express .


4, Autoriteit 9%

Maak gebruik van het MVC-filtersysteem en Global.Asax.cs, ik neem aan dat je dit zou kunnen doen …

   protected void Application_Start()
    {
      RegisterGlobalFilters(GlobalFilters.Filters);
    }
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
      filters.Add(new HandleErrorAttribute());
      if(Config.IsProduction) //Some flag that you can tell if you are in your production environment.
      {
        filters.Add(new RequireHttpsAttribute());
      }
    }

5, Autoriteit 8%

Omdat het de ASP.NET-ontwikkelingsserver was die uw probleem in de eerste plaats heeft veroorzaakt, is het vermeldenswaard dat Microsoft nu IIS Express , die schepen met Visual Studio (sinds VS2010 SP1). Dit is een uitgesneden versie van IIS die zo eenvoudig te gebruiken is als de ontwikkelingsserver, maar ondersteunt de volledige functieset van IIS 7.5 inclusief SSL.

Scott Hanselman heeft een gedetailleerde post op Werken met SSL in IIS Express .


6, Autoriteit 7%

Hoe zit het met het erven van het kenmerk van de vereistehtts in een aangepast attribuut. Dan, in uw aangepaste kenmerk, controleer de islocal-eigendom van het huidige verzoek om te zien of het verzoek uit de lokale machine komt. Als het is, breng dan de basisfunctionaliteit niet aan. Bel anders, bel de basisbewerking.


7, Autoriteit 3%

Dit werkte voor mij, MVC 6 (ASP.NET-kern 1.0) .
Codecontroles als debug in ontwikkeling is, en zo niet, is SSL niet vereist.
Alle bewerkingen staan ​​in startup.cs .

Toevoegen:

private IHostingEnvironment CurrentEnvironment { get; set; }

Toevoegen:

public Startup(IHostingEnvironment env)
{
    CurrentEnvironment = env;
}

EDIT:

public void ConfigureServices(IServiceCollection services)
{
    // additional services...
    services.AddMvc(options =>
    {
        if (!CurrentEnvironment.IsDevelopment())
        {
            options.Filters.Add(typeof(RequireHttpsAttribute));
        }
    });
}

8, Autoriteit 2%

Als u kunt afleiden en negeren – doe het dan. Als u dat niet kunt – MVC wordt geleverd met bronnen, neemt u de bronnen en maakt u uw eigen [FUCKHTTPS] -attribuut die islocal controleert.


9, Autoriteit 2%

Voor MVC 3 Ik heb mijn eigen filterprovider toegevoegd (op basis van code gevonden: Wereldwijde en voorwaardelijke filters dat, onder andere (Debug-info voor lokale gebruikers enz.) Wordt alle acties met RequireHttpsAttributedecoreren wanneer HttpContext.Request.IsLocal == false.


Antwoord 10, autoriteit 2%

Eén oplossing die u zowel op productie- als ontwikkelingswerkstations kunt gebruiken. Het is gebaseerd op uw optie uit de applicatie-instellingen in web.config

<appSettings>
     <!--Use SSL port 44300 in IIS Express on development workstation-->
     <add key="UseSSL" value="44300" />
</appSettings>

Als u geen SSL wilt gebruiken, verwijdert u de sleutel. Als u standaard SSL-poort 443 gebruikt, verwijder dan de waarde of specificeer 443.

Gebruik vervolgens de aangepaste implementatie van RequireHttpsAttributedie voor uw aandoening zorgt. Het is eigenlijk afgeleid van RequireHttpsen gebruikt dezelfde implementatie van de basismethode, behalve voor het toevoegen van voorwaarden.

public class RequireHttpsConditional : RequireHttpsAttribute
{
    protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
    {
        var useSslConfig = ConfigurationManager.AppSettings["UseSSL"];
        if (useSslConfig != null)
        {
            if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException("The requested resource can only be accessed via SSL.");
            }
            var request = filterContext.HttpContext.Request;
            string url = null;
            int sslPort;
            if (Int32.TryParse(useSslConfig, out sslPort) && sslPort > 0)
            {
                url = "https://" + request.Url.Host + request.RawUrl;
                if (sslPort != 443)
                {
                    var builder = new UriBuilder(url) {Port = sslPort};
                    url = builder.Uri.ToString();
                }
            }
            if (sslPort != request.Url.Port)
            {
                filterContext.Result = new RedirectResult(url);
            }
        }
    }
}

Vergeet niet om de LogOn-methode in AccountController te versieren

[RequireHttpsConditional]
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)

en zoiets in uw LogOn-weergave om het formulier via https te posten.

<% using (Html.BeginFormSecure("LogOn", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] }, Request.IsSecureConnection, Request.Url)) { %>

11

MVC 6 (ASP.NET Core 1.0):

De juiste oplossing zou zijn om ENV.IsProduction () of env.isde ontwikkeling () te gebruiken. Lees meer over reden achter in dit antwoord op Hoe moet u HTTPS alleen in productie vereisen.

Gecondenseerd antwoord hieronder (zie link hierboven om meer te lezen over ontwerpbeslissingen) voor 2 verschillende stijlen:

  1. startup.cs – registreer filter
  2. Basecontroller – attribuutstijl

startup.cs (registreren filter):

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

basecontroller.cs (attribuut stijl):

[RequireHttpsInProductionAttribute]
public class BaseController : Controller
{
    // Maybe you have other shared controller logic..
}
public class HomeController : BaseController
{
    // Add endpoints (GET / POST) for Home controller
}

vereistehtpsinproductionattribute :
Beide bovenstaande zijn het gebruik van aangepast attribuut erven van vereistehttpsattribute :

public class RequireHttpsInProductionAttribute : RequireHttpsAttribute
{
    private bool IsProduction { get; }
    public RequireHttpsInProductionAttribute(IHostingEnvironment environment)
    {
        if (environment == null)
            throw new ArgumentNullException(nameof(environment));
        this.IsProduction = environment.IsProduction(); 
    }
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (this.IsProduction)
            base.OnAuthorization(filterContext);
    }
    protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
    {
        if(this.IsProduction)
            base.HandleNonHttpsRequest(filterContext);
    }
}

12

Dit was de schoonste manier voor mij. In mijn App_Start\FilterConfig.csbestand. Kan geen release-builds meer uitvoeren.

... 
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
        if (!Web.HttpContext.Current.IsDebuggingEnabled) {
            filters.Add(new RequireHttpsAttribute());   
        }
        ...
}

U kunt ook instellen dat u alleen HTTPS nodig hebt wanneer uw aangepaste foutpagina is ingeschakeld.

... 
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
        if (Web.HttpContext.Current.IsCustomErrorEnabled) {
            filters.Add(new RequireHttpsAttribute());   
        }
        ...
}

13

Raadpleeg dit bericht door Rick Anderson op RickandmsFT op Azure & AMP; MVC vult de Azure Gap

http://blogs.msDN.com/b/rickandy/archive/2011/04/22/Better-faster-asier-Ssl-testing-for-aSp-Net-Mvc- Amp-Webform.aspx

Other episodes