프로덕션에서만 ASP.NET MVC RequireHttps


121

RequireHttpsAttribute 를 사용하고 싶습니다.보안되지 않은 HTTP 요청이 작업 메서드로 전송되지 않도록 .

씨#

[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

불행히도 ASP.NET 개발 서버는 HTTPS를 지원하지 않습니다.

ASP.NET MVC 응용 프로그램이 프로덕션 환경에 게시 될 때 RequireHttps를 사용하도록 만들 수 있지만 ASP.NET 개발 서버의 개발 워크 스테이션에서 실행할 때는 어떻게해야합니까?


3
로컬 IIS 및 IIS Express로 테스트하십시오. 내 SSL 블로그를 참조 blogs.msdn.com/b/rickandy/archive/2011/04/22/...blogs.msdn.com/b/rickandy/archive/2012/03/23/...
RickAndMSFT

답변:


129

개발 워크 스테이션에서 릴리스 빌드를 실행하는 경우에는 도움이되지 않지만 조건부 컴파일이 작업을 수행 할 수 있습니다.

#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()
    {
    }

}

최신 정보

Visual Basic에서 특성은 기술적으로 적용되는 정의와 동일한 줄의 일부입니다. 조건부 컴파일 문을 한 줄에 넣을 수 없으므로 함수 선언을 두 번 작성해야합니다. 한 번은 속성을 포함하고 한 번은 포함하지 않습니다. 하지만 추악함에 신경 쓰지 않으면 작동합니다.

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

업데이트 2

여러 사람들이 RequireHttpsAttribute예제를 제공하지 않고 파생되었다고 언급 했으므로 여기에 하나가 있습니다. 이 접근 방식이 조건부 컴파일 접근 방식보다 훨씬 깨끗할 것이라고 생각하며 귀하의 입장에서 선호하는 것입니다.

면책 조항 :이 코드를 조금이라도 테스트하지 않았으며 VB는 상당히 녹슬 었습니다. 내가 아는 것은 그것이 컴파일된다는 것입니다. 나는 spot, queen3, Lance Fisher의 제안을 바탕으로 썼다. 작동하지 않으면 최소한 일반적인 아이디어를 전달하고 시작점을 제공해야합니다.

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

기본적으로 현재 요청이 로컬 인 경우 (즉, localhost를 통해 사이트에 액세스하는 경우) 기본 SSL 인증 코드를 실행하는 대신 새 속성이 종료됩니다. 다음과 같이 사용할 수 있습니다.

<RemoteRequireHttps()> _
Public Class SomeController

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

End Class

훨씬 더 깨끗해! 테스트되지 않은 코드가 실제로 작동한다면.


글을 수정 해줘서 고마워, 잭 귀하의 질문은 C #에 있었으므로 C # 응답을 게시했습니다. VB가 관련이 있는지 몰랐습니다. 조건부 컴파일을 사용하여 VB의 속성을 제어하는 ​​방법이 있는지 아는 사람이 있습니까? 아니면 가능하지 않습니까?
Joel Mueller

예, C #에서 작동하고 VB에서도 작동하지만 함수 / 클래스 정의를 다소 추악하게 복제해야합니다. 위의 업데이트 된 답변을 참조하십시오.
Joel Mueller

죄송합니다. VB 코드 샘플은 점점 더 어려워지고 있습니다. 나는 그것이 중요 할 것이라고 생각하지 않았다. 원래 질문을 업데이트했습니다. 속성에 대한 조건부 컴파일이 C #에서 확실히 작동합니까? 나는 테스트하지 않았습니다. 완벽하고 우아한 솔루션 인 것 같습니다.
Zack Peterson

RemoteRequireHttpsAttribute 코드가 완벽하게 작동합니다. VB에서는 조건부 컴파일보다 훨씬 더 우아합니다. 다시 한 번 감사합니다 Joel.
Zack Peterson

2
고마워요.이게 바로 제가 필요했던 것입니다. 건배!
davecoulter

65

누구든지 C # 버전이 필요한 경우 :

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

읽을 때 확인 보안 조치로 우리는 추가해야합니다 filters.Add(new MyRequireHttpsAttribute ());FilterConfig?
shaijut

이 답변을 바탕으로 Startup.cs의 필터 또는 Controller의 속성 스타일을 사용하여 MVC 6에 대한 솔루션을 만들었습니다 .
Nick Niebling 2016-07-07

26

RequireHttps에서 파생하는 것은 좋은 접근 방식입니다.

문제를 완전히 해결하려면 자체 서명 된 인증서로 로컬 컴퓨터에서 IIS를 사용할 수도 있습니다. IIS는 기본 제공 웹 서버보다 빠르며 개발 환경이 프로덕션과 비슷하다는 이점이 있습니다.

Scott Hanselman은 VS2010 및 IIS Express로 로컬 HTTPS를 구현하는 몇 가지 방법에 대한 훌륭한 리소스를 보유하고 있습니다.


ya-Mifi wifi Verizon 장치로 포트 포워딩을 시도하고 포트 443을 포워딩 할 수 없음을 알 때까지 !!! # * & # * & $
Simon_Weaver 2011

자체 서명 된 인증서를 사용하여 로컬 컴퓨터에서 IIS를 사용하는 것이 마음에 들지 않는 점은 변경 사항을 테스트하기 위해 추가 배포 단계를 거쳐야한다는 것입니다. 나는 당신이 말이되는 것보다 보안과 관련된 것을 테스트하고 있다고 생각하지만, 단지 다른 사소한 변경 사항을 확인하고 있다면, HTTPS를 지원하는 Cassini의 무능력을 피하기 위해 배포해야하는 고통이라고 생각합니다.
davecoulter

1
@davecoulter-클라이언트 버전의 Windows에서 IIS Express를 사용하고 cassini가 필요하지 않으며 ssl 기능을 포함하여 IIS와 똑같이 작동합니다.
Erik Funkenbusch 2011-08-26

@Mystere Man-네, 그 댓글 이후로 알아 냈습니다. 팁 : 감사합니다
davecoulter

그러한 일을 수행하는 방법에 대한 더 많은 정보 또는 링크가 추가되어야합니다.
stephenbayer 2014-08-25

12

MVC 필터 시스템과 Global.asax.cs를 활용하여이 작업을 수행 할 수 있다고 가정합니다.

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

이 답변은 모든 단일 요청에 대해 실행 / 호출 될 새로운 필터를 구현하는 것보다 애플리케이션 수 명당 하나의 검사를 포함하기 때문에 선호합니다.
Abdulhameed

10

처음에 문제를 일으킨 것은 ASP.Net Development Server 였기 때문에 Microsoft는 이제 Visual Studio (VS2010 SP1 이후)와 함께 제공되는 IIS Express를 보유하고 있다는 점에 주목할 가치가 있습니다. 이것은 개발 서버만큼 사용하기 쉽지만 SSL을 포함한 IIS 7.5의 전체 기능 세트를 지원하는 IIS의 축소 버전입니다.

Scott Hanselman은 IIS Express에서 SSL 작업 에 대한 자세한 게시물을 보유하고 있습니다.


9

사용자 지정 특성에서 RequireHttps 특성을 상속하는 방법은 무엇입니까? 그런 다음 사용자 지정 특성 내에서 현재 요청의 IsLocal 속성을 확인하여 요청이 로컬 컴퓨터에서 오는지 확인합니다. 그렇다면 기본 기능을 적용하지 마십시오. 그렇지 않으면 기본 작업을 호출합니다.


4

이것은 나를 위해 MVC 6 (ASP.NET Core 1.0) . 코드는 디버그가 개발 중인지 확인하고 그렇지 않은 경우 ssl이 필요하지 않습니다. 모든 편집은 Startup.cs에 있습니다.

더하다:

private IHostingEnvironment CurrentEnvironment { get; set; }

더하다:

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

편집하다:

public void ConfigureServices(IServiceCollection services)
{
    // additional services...

    services.AddMvc(options =>
    {
        if (!CurrentEnvironment.IsDevelopment())
        {
            options.Filters.Add(typeof(RequireHttpsAttribute));
        }
    });
}

3

파생하고 재정의 할 수 있다면 그렇게하십시오. 할 수없는 경우-MVC는 소스와 함께 제공됩니다. 소스를 가져 와서 IsLocal을 확인하는 고유 한 [ForceHttps] 속성을 만듭니다.


3

MVC 3의 경우 내 자신의 FilterProvider (여기에있는 코드를 기반으로 : 전역 및 조건부 필터를 추가 했습니다.이 필터 는 로컬 사용자에 대한 디버그 정보 표시 등)가 모든 작업을 RequireHttpsAttribute언제 HttpContext.Request.IsLocal == false.


또는 요청이 로컬 인 경우 조건부로 전역 필터 컬렉션에 추가 할 수 있습니다. 요청을 사용할 수 없을 수 있으므로 앱이 즉시 시작되도록 설정된 경우 try / catch 블록에서이를 확인해야합니다.
tvanfosson 2011-07-05

3

aroud를 조사한 후 IIS Express와 Controller 클래스의 OnAuthorization 메서드 (Ref # 1)를 재정 의하여이 문제를 해결할 수있었습니다. 나는 또한 Hanselman이 추천하는 경로 (Ref # 2)로 갔다. 그러나 두 가지 이유 때문에이 두 가지 솔루션에 만족하지 못했습니다. 1. Ref # 1의 OnAuthorization은 컨트롤러 클래스 수준이 아닌 액션 수준에서만 작동합니다. 2. Ref # 2에는 많은 설정이 필요합니다 (makecert 용 Win7 SDK ), netsh 명령, 그리고 포트 80과 포트 443을 사용하려면 VS2010을 관리자 권한으로 시작해야하는데,이 점이 인상적입니다.

그래서 저는 다음과 같은 조건에서 단순성에 초점을 맞춘이 솔루션을 생각해 냈습니다.

  1. 컨트롤러 클래스 또는 작업 수준에서 RequireHttps attbbute를 사용할 수 있기를 원합니다.

  2. RequireHttps 속성이있을 때 MVC에서 HTTPS를 사용하고 없으면 HTTP를 사용하고 싶습니다.

  3. Visual Studio를 관리자로 실행할 필요가 없습니다.

  4. IIS Express에서 할당 한 모든 HTTP 및 HTTPS 포트를 사용하고 싶습니다 (참고 # 1 참조).

  5. IIS Express의 자체 서명 된 SSL 인증서를 재사용 할 수 있으며 잘못된 SSL 프롬프트가 표시 되어도 상관 없습니다.

  6. 개발, 테스트 및 프로덕션이 동일한 코드베이스와 동일한 바이너리를 사용하고 가능한 한 추가 설정 (예 : netsh, mmc cert 스냅인 등 사용)과 독립적으로 사용하기를 원합니다.

이제 배경과 설명을 제외하고이 코드가 누군가를 돕고 시간을 절약하기를 바랍니다. 기본적으로 Controller에서 상속하는 BaseController 클래스를 만들고이 기본 클래스에서 컨트롤러 클래스를 파생시킵니다. 지금까지 읽었으므로이 작업을 수행하는 방법을 알고 있다고 가정합니다. 자, 행복한 코딩!

Note # 1 : 이것은 유용한 함수 'getConfig'(코드 참조)를 사용하여 이루어집니다.

참조 # 1 : http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html

참조 # 2 : http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx

========== BaseController의 코드 ==================

     #region Override to reroute to non-SSL port if controller action does not have RequireHttps attribute to save on CPU 
    // By L. Keng, 2012/08/27
    // Note that this code works with RequireHttps at the controller class or action level.
    // Credit: Various stackoverflow.com posts and http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        // if the controller class or the action has RequireHttps attribute
        var requireHttps = (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0 
                            || filterContext.ActionDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0);
        if (Request.IsSecureConnection)
        {
            // If request has a secure connection but we don't need SSL, and we are not on a child action   
            if (!requireHttps && !filterContext.IsChildAction)
            {
                var uriBuilder = new UriBuilder(Request.Url)
                {
                    Scheme = "http",
                    Port = int.Parse(getConfig("HttpPort", "80")) // grab from config; default to port 80
                };
                filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
            }
        }
        else
        {
            // If request does not have a secure connection but we need SSL, and we are not on a child action   
            if (requireHttps && !filterContext.IsChildAction)
            {
                var uriBuilder = new UriBuilder(Request.Url)
                {
                    Scheme = "https",
                    Port = int.Parse(getConfig("HttpsPort", "443")) // grab from config; default to port 443
                };
                filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
            }
        }
        base.OnAuthorization(filterContext);
    }
    #endregion

    // a useful helper function to get appSettings value; allow caller to specify a default value if one cannot be found
    internal static string getConfig(string name, string defaultValue = null)
    {
        var val = System.Configuration.ConfigurationManager.AppSettings[name];
        return (val == null ? defaultValue : val);
    }

============== 종료 코드 ===============

Web.Release.Config에서 다음을 추가하여 HttpPort 및 HttpsPort를 지우십시오 (기본값 80 및 443 사용).

<appSettings>
<add key="HttpPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
<add key="HttpsPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
</appSettings>

3

프로덕션 및 개발 워크 스테이션에서 사용할 수있는 하나의 솔루션입니다. web.config의 애플리케이션 설정에있는 옵션을 기반으로합니다.

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

SSL을 사용하지 않으려면 키를 제거하십시오. 표준 SSL 포트 443을 사용하는 경우 값을 제거하거나 443을 지정하십시오.

그런 다음 조건을 처리하는 RequireHttpsAttribute의 사용자 지정 구현을 사용 합니다. 실제로 RequireHttps 에서 파생되며 조건 추가를 제외하고는 동일한 기본 메서드 구현을 사용합니다.

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

AccountController에서 LogOn 메서드 를 장식하는 것을 잊지 마십시오.

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

https를 통해 양식을 게시하기 위해 LogOn View에 이와 비슷한 내용이 있습니다 .

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

이 오류가 발생합니다 : XMLHttpRequest cannot load m.XXX.com/Auth/SignIn . 요청 된 리소스에 'Access-Control-Allow-Origin'헤더가 없습니다. 따라서 출처 ' m.XXX.com '은 액세스가 허용되지 않습니다.
Ranjith Kumar Nagiri

2

Joel이 언급했듯이 #if !DEBUG지시문 을 사용하여 컴파일을 변경할 수 있습니다 .

방금 web.config 파일 컴파일 요소에서 DEBUG 기호의 값을 변경할 수 있다는 것을 알았습니다. 도움이되기를 바랍니다.


1

MVC 6 (ASP.NET Core 1.0) :

적절한 해결책은 env.IsProduction () 또는 env.IsDevelopment ()를 사용하는 것입니다. 프로덕션에서만 https를 요구하는 방법대한 이 답변의 이유에 대해 자세히 알아보십시오 .

두 가지 스타일에 대한 아래 요약 된 답변 (디자인 결정에 대한 자세한 내용은 위 링크 참조) :

  1. Startup.cs-레지스터 필터
  2. BaseController-속성 스타일

Startup.cs (등록 필터) :

public void ConfigureServices(IServiceCollection services)
{
    // TODO: Register other services

    services.AddMvc(options =>
    {
        options.Filters.Add(typeof(RequireHttpsInProductionAttribute));
    });
}

BaseController.cs (속성 스타일) :

[RequireHttpsInProductionAttribute]
public class BaseController : Controller
{
    // Maybe you have other shared controller logic..
}

public class HomeController : BaseController
{
    // Add endpoints (GET / POST) for Home controller
}

RequireHttpsInProductionAttribute : 위의 두 가지 모두 RequireHttpsAttribute 에서 상속 된 사용자 지정 특성을 사용하고 있습니다 .

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

1

이것은 나에게 가장 깨끗한 방법이었습니다. 내 App_Start\FilterConfig.cs파일에서. 더 이상 릴리스 빌드를 실행할 수 없습니다.

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

또는 사용자 지정 오류 페이지가 켜져있을 때 https 만 요구하도록 설정할 수 있습니다.

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

이것은 MVC 5에서 훌륭하게 작동하는 쉬운 솔루션입니다. :)
MWD

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.