보안 프레임: 예외 관리 | 해결 방법

제품/서비스 아티클
WCF
웹 API
웹 애플리케이션

WCF - 구성 파일에 serviceDebug 노드를 포함하지 않음

타이틀 세부 정보
구성 요소 WCF
SDL 단계 빌드
적용 가능한 기술 일반, .NET Framework 3
특성 해당 없음
참조 MSDN, Fortify, 영국
단계 WCF(Windows Communication Framework) 서비스는 디버깅 정보를 노출하도록 구성할 수 있습니다. 디버그 정보를 프로덕션 환경에서는 사용하지 않아야 합니다. <serviceDebug> 태그는 WCF 서비스에 대해 디버그 정보 기능이 사용되는지 여부를 정의합니다. 특성 includeExceptionDetailInFaults를 true로 설정하면 애플리케이션에서 예외 정보가 클라이언트로 반환됩니다. 공격자는 디버깅 출력에서 얻은 추가 정보를 활용하여 프레임워크, 데이터베이스 또는 애플리케이션이 사용하는 기타 리소스를 대상으로 공격을 수행할 수 있습니다.

예시

다음 구성 파일에는 <serviceDebug> 태그가 포함됩니다.

<configuration> 
<system.serviceModel> 
<behaviors> 
<serviceBehaviors> 
<behavior name=""MyServiceBehavior""> 
<serviceDebug includeExceptionDetailInFaults=""True"" httpHelpPageEnabled=""True""/> 
... 

서비스에서 디버깅 정보를 사용하지 않도록 설정합니다. 이 작업은 애플리케이션 구성 파일에서 <serviceDebug> 태그를 제거하여 수행할 수 있습니다.

WCF - 구성 파일에 serviceMetadata 노드를 포함하지 않음

타이틀 세부 정보
구성 요소 WCF
SDL 단계 빌드
적용 가능한 기술 일반
특성 일반, .NET Framework 3
참조 MSDN, Fortify, 영국
단계 서비스에 대한 정보를 공개적으로 노출하면 공격자는 서비스를 악용하는 방법에 대한 중요한 아이디어를 얻을 수 있습니다. <serviceMetadata> 태그는 메타데이터 게시 기능을 사용하도록 설정합니다. 서비스 메타데이터에는 공개적으로 액세스할 수 없게 해야 하는 중요한 정보가 포함될 수 있습니다. 적어도, 신뢰할 수 있는 사용자만 메타데이터에 액세스하도록 허용하고 불필요한 정보가 노출되지 않도록 해야 합니다. 더 나아가 메타데이터를 게시하는 기능은 완전히 사용하지 않도록 설정해야 합니다. 안전한 WCF 구성에는 <serviceMetadata> 태그가 포함되지 않습니다.

ASP.NET Web API에서 적절한 예외 처리가 수행되었는지 확인

타이틀 세부 정보
구성 요소 웹 API
SDL 단계 빌드
적용 가능한 기술 MVC 5, MVC 6
특성 해당 없음
참조 ASP.NET Web API에서 예외 처리, ASP.NET Web API의 모델 유효성 검사
단계 기본적으로 ASP.NET Web API에서 확인할 수 없는 대부분의 예외는 500, Internal Server Error 상태 코드의 HTTP 응답으로 변환됩니다.

예시

API에서 반환되는 상태 코드를 제어하려면 아래와 같이 HttpResponseException을 사용할 수 있습니다.

public Product GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    return item;
}

예시

예외 응답을 추가적으로 제어하려면 아래와 같이 HttpResponseMessage 클래스를 사용할 수 있습니다.

public Product GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
        {
            Content = new StringContent(string.Format("No product with ID = {0}", id)),
            ReasonPhrase = "Product ID Not Found"
        }
        throw new HttpResponseException(resp);
    }
    return item;
}

HttpResponseException 형식이 아닌 처리되지 않은 예외를 catch하려면 예외 필터를 사용할 수 있습니다. 예외 필터는 System.Web.Http.Filters.IExceptionFilter 인터페이스를 구현합니다. 예외 필터를 작성하는 가장 간단한 방법은 System.Web.Http.Filters.ExceptionFilterAttribute 클래스에서 파생하고 OnException 메서드를 재정의하는 것입니다.

예시

다음은 NotImplementedException을 HTTP 상태 코드 501, Not Implemented로 변환하는 필터입니다.

namespace ProductStore.Filters
{
    using System;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http.Filters;

    public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute 
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            if (context.Exception is NotImplementedException)
            {
                context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
            }
        }
    }
}

다음과 같은 여러 가지 방법으로 Web API 예외 필터를 등록할 수 있습니다.

  • 작업 기준
  • 컨트롤러 기준
  • 전역적으로

예시

특정 작업에 필터를 적용하려면 필터를 작업에 특성으로 추가합니다.

public class ProductsController : ApiController
{
    [NotImplExceptionFilter]
    public Contact GetContact(int id)
    {
        throw new NotImplementedException("This method is not implemented");
    }
}

예시

controller의 모든 작업에 필터를 적용하려면 필터를 controller 클래스에 특성으로 추가합니다.

[NotImplExceptionFilter]
public class ProductsController : ApiController
{
    // ...
}

예시

모든 Web API 컨트롤러에는 전역적으로 필터를 적용하려면 필터의 인스턴스를 GlobalConfiguration.Configuration.Filters 컬렉션에 추가합니다. 이 컬렉션의 예외 필터는 모든 Web API 컨트롤러 작업에 적용됩니다.

GlobalConfiguration.Configuration.Filters.Add(
    new ProductStore.NotImplExceptionFilterAttribute());

예시

모델 유효성 검사를 위해 모델 상태를 아래와 같이 CreateErrorResponse 메서드에 전달할 수 있습니다.

public HttpResponseMessage PostProduct(Product item)
{
    if (!ModelState.IsValid)
    {
        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
    }
    // Implementation not shown...
}

ASP.NET Web API의 예외 처리 및 모델 유효성 검사에 대한 자세한 내용은 참조 섹션의 링크를 확인하세요.

오류 메시지에 보안 정보를 노출하지 않음

타이틀 세부 정보
구성 요소 웹 애플리케이션
SDL 단계 빌드
적용 가능한 기술 일반
특성 해당 없음
참조 해당 없음
단계

일반 오류 메시지는 중요한 애플리케이션 데이터를 포함하지 않고 사용자에게 직접 제공됩니다. 중요한 데이터의 예는 다음과 같습니다.

  • 서버 이름
  • 연결 문자열
  • 사용자 이름
  • 암호
  • SQL 프로시저
  • 동적 SQL 오류의 세부 정보
  • 스택 추적 및 코드 줄
  • 메모리에 저장된 변수
  • 드라이브 및 폴더 위치
  • 애플리케이션 설치 지점
  • 호스트 구성 설정
  • 기타 내부 애플리케이션 정보

애플리케이션 내의 모든 오류를 트래핑하고 일반 오류 메시지를 제공할 뿐 아니라 IIS 내에서 사용자 지정 오류를 사용하도록 설정하면 정보가 공개되지 않도록 하는 데 도움이 됩니다. 다른 오류 처리 아키텍처 중에서 SQL Server Database 및 .NET 예외 처리는 사용자 애플리케이션을 프로파일링하는 악의적인 사용자에게 특히 유용할 수 있습니다. .NET 예외 클래스에서 파생된 클래스의 내용을 직접 표시하지 않도록 하고, 예기치 않은 예외가 사용자에게 실수로 직접 표시되지 않도록 적절한 예외 처리를 진행합니다.

  • 예외/오류 메시지에서 직접 확인되는 특정 세부 정보를 추상화하는 일반적인 오류 메시지를 사용자에게 제공합니다.
  • .NET 예외 클래스의 내용을 사용자에게 직접 표시하지 않습니다.
  • 모든 오류 메시지를 트래핑하고, 해당하는 경우 애플리케이션 클라이언트에 전송된 일반 오류 메시지를 통해 사용자에게 알립니다.
  • 예외 클래스의 내용, 특히 .ToString()의 반환 값 또는 Message 또는 StackTrace 속성 값을 사용자에게 직접 공개하지 않습니다. 이 정보를 안전하게 기록하고 사용자에게는 좀 더 무해한 메시지를 표시합니다.

기본 오류 처리 페이지 구현

타이틀 세부 정보
구성 요소 웹 애플리케이션
SDL 단계 빌드
적용 가능한 기술 일반
특성 해당 없음
참조 ASP.NET 오류 페이지 설정 대화 상자 편집
단계

ASP.NET 애플리케이션이 실패하고 HTTP/1.x 500 내부 서버 오류가 발생하거나 기능 구성(예: 요청 필터링)으로 인해 페이지가 표시되지 않을 경우 오류 메시지가 생성됩니다. 관리자는 애플리케이션이 클라이언트에 자세한 오류 메시지를 표시할지 또는 localhost에만 자세한 오류 메시지를 표시할지를 선택할 수 있습니다. web.config의 <customErrors> 태그는 다음 세 가지 모드로 제공됩니다.

  • On: 사용자 지정 오류가 사용되도록 지정합니다. defaultRedirect 특성을 지정하지 않으면 사용자에게 일반 오류가 표시됩니다. 원격 클라이언트 및 로컬 호스트에 사용자 지정 오류가 표시됩니다.
  • Off: 사용자 지정 오류가 사용되지 않도록 지정합니다. 원격 클라이언트 및 로컬 호스트에 자세한 ASP.NET 오류가 표시됩니다.
  • RemoteOnly: 사용자 지정 오류가 원격 클라이언트에만 표시되고 로컬 호스트에는 ASP.NET 오류가 표시되도록 지정합니다. 이 값이 기본값입니다.

애플리케이션/사이트에 대한 web.config 파일을 열고 태그에 <customErrors mode="RemoteOnly" /> 또는 <customErrors mode="On" />이 정의되어 있는지 확인합니다.

IIS에서 배포 방법을 일반 정품으로 설정

타이틀 세부 정보
구성 요소 웹 애플리케이션
SDL 단계 배포
적용 가능한 기술 일반
특성 해당 없음
참조 배포 요소(ASP.NET 설정 스키마)
단계

<deployment retail> 스위치는 프로덕션 IIS 서버에서 사용되도록 고안되었습니다. 이 스위치는 애플리케이션이 페이지에서 추적 출력을 생성하는 기능을 사용하지 않도록 설정하고, 최종 사용자에게 자세한 오류 메시지를 표시하는 기능을 사용하지 않도록 설정하고, 디버그 스위치를 사용하지 않도록 설정하여 성능을 최대화하고 보안 정보 노출을 최소화하도록 도와줍니다.

종종 활성 개발 중에 실패한 요청 추적 및 디버그와 같은 개발자 중심의 스위치 및 옵션이 사용됩니다. 프로덕션 서버의 배포 방법을 일반 정품으로 설정하는 것이 좋습니다. machine.config 파일을 열고 <deployment retail="true" />을 true 상태로 유지합니다.

안전한 예외 실패

타이틀 세부 정보
구성 요소 웹 애플리케이션
SDL 단계 빌드
적용 가능한 기술 일반
특성 해당 없음
참조 안전하게 실패
단계 애플리케이션은 안전하게 실패해야 합니다. 수행되는 특정 결정에 따라 부울 값을 반환하는 모든 메서드는 신중하게 예외 블록을 만들어야 합니다. 부주의하게 예외 블록이 작성되면 보안 문제로 인한 논리적 오류가 많이 발생합니다.

예시

        public static bool ValidateDomain(string pathToValidate, Uri currentUrl)
        {
            try
            {
                if (!string.IsNullOrWhiteSpace(pathToValidate))
                {
                    var domain = RetrieveDomain(currentUrl);
                    var replyPath = new Uri(pathToValidate);
                    var replyDomain = RetrieveDomain(replyPath);

                    if (string.Compare(domain, replyDomain, StringComparison.OrdinalIgnoreCase) != 0)
                    {
                        //// Adding additional check to enable CMS urls if they are not hosted on same domain.
                        if (!string.IsNullOrWhiteSpace(Utilities.CmsBase))
                        {
                            var cmsDomain = RetrieveDomain(new Uri(Utilities.Base.Trim()));
                            if (string.Compare(cmDomain, replyDomain, StringComparison.OrdinalIgnoreCase) != 0)
                            {
                                return false;
                            }
                            else
                            {
                                return true;
                            }
                        }

                        return false;
                    }
                }

                return true;
            }
            catch (UriFormatException ex)
            {
                LogHelper.LogException("Utilities:ValidateDomain", ex);
                return true;
            }
        }

예외가 발생하면 항상 위 메서드는 True를 반환합니다. 최종 사용자가 잘못된 형식의 URL을 제공할 경우 브라우저는 이를 유지하지만 Uri() 생성자는 그렇지 않을 경우 예외가 throw되며 사용자는 유효하지만 형식이 잘못된 URL을 사용하게 됩니다.