보안: Web API에서 SSL 사용하기

등록일시: 2014-02-05 08:00,  수정일시: 2014-01-30 12:36
조회수: 19,879
이 문서는 ASP.NET Web API 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.

몇 가지 보편적인 인증 스킴들은 평문 HTTP 상에서는 안전하지 않으며, 특히 기본 인증과 폼 인증은 암호화되지 않은 자격 증명을 전송하기 때문에 더욱 그러합니다. 따라서, 안전을 보장하려면 이런 인증 스킴들은 반드시 SSL과 함께 사용해야 합니다. 또한, SSL 클라이언트 인증서를 클라이언트 인증에 사용할 수도 있습니다.

서버에서 SSL 활성화하기

IIS 7이나 그 이상에서 SSL을 설정하려면:

  • 인증서를 생성하거나 발급받습니다. 테스트 용도로 자체-서명 인증서(Self-Signed Certificate)를 생성할 수도 있습니다.
  • HTTPS 바인딩을 추가합니다.

이에 대한 보다 자세한 내용은 How to Set Up SSL on IIS 7 문서를 참고하시기 바랍니다.

로컬 테스트를 위해서 Visual Studio에서 IIS 익스프레스의 SSL을 활성화시킬 수도 있습니다. 그러려면, 프로젝트의 속성(Properties) 창에서 SSL 사용(SSL Enabled) 항목의 값을 True로 설정합니다. * 그리고, 다음 이미지의 SSL URL 항목의 값에 주의하시기 바랍니다. HTTPS 연결 테스트를 수행하려면 이런 URL을 사용해야 합니다. **

* 프로젝트의 속성 창을 열려면 솔루션 탐색기에서 프로젝트 노드를 클릭한 다음, F4 키를 누릅니다

** 기본적으로 IIS 익스프레스는 44300번 부터 44399번 사이의 포트를 통해서 SSL을 사용할 수 있도록 구성됩니다. 더 자세한 내용은 IIS 익스프레스 FAQ 문서의 "Q: IIS 익스프레스는 SSL을 지원합니까?" 질문을 참고하시기 바랍니다.

Web API 컨트롤러에서 SSL을 강제하기

만약, HTTPS 바인딩과 HTTP 바인딩이 모두 구성되어 있다면 클라이언트는 계속해서 HTTP로도 사이트에 접근할 수 있습니다. 이런 상황에서 일부 리소스들은 HTTP를 통한 접근을 허용하는 반면, 그 외의 리소스들은 SSL을 통해서만 접근할 수 있도록 구성하고 싶을 수도 있습니다. 그런 경우에, 액션 필터를 사용해서 보호하고자 하는 리소스들에 SSL을 통해서만 접근할 수 있도록 강제할 수 있습니다. 다음 코드는 SSL 접근 여부를 확인하는 Web API 인증 필터를 보여줍니다:

public class RequireHttpsAttribute : AuthorizationFilterAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        if (actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps)
        {
            actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
            {
                ReasonPhrase = "HTTPS Required"
            };
        }
        else
        {
            base.OnAuthorization(actionContext);
        }
    }
}

이 필터를 SSL을 강제하고자 하는 Web API 액션에 추가하면 됩니다:

public class ValuesController : ApiController
{
    [RequireHttps]
    public HttpResponseMessage Get() { ... }
}

SSL 클라이언트 인증서

SSL은 공개 키 기반구조 인증서를 이용한 인증을 제공해줍니다. 이 방식에서 서버는 서버를 인증하는 인증서를 클라이언트에게 제공해야 합니다. 클라이언트 쪽에서 서버에 인증서를 제공하는 경우는 드물지만, 이 방법 역시 클라이언트를 인증할 수 있는 방법 중 한 가지입니다. SSL과 함께 클라이언트 인증서를 사용하려면 서명된 인증서를 사용자들에게 배포할 수 있는 방안이 필요합니다. 대부분의 응용 프로그램 형태에서 이는 그다지 좋은 사용자 경험을 제공해주지는 못하지만, 일부 환경에는(기업 내부 환경 등) 적합할 수도 있습니다.

장점 단점
  • 인증서 자격 증명이 사용자 이름/비밀번호 조합보다 강력함
  • SSL이 완전한 보안 채널, 인증, 메시지 무결성, 그리고 메시지 암호화를 제공해줌
  • PKI 인증서를 발급받고 관리해야 함
  • 클라이언트 플랫폼에서 반드시 SSL 클라이언트 인증서를 지원해야 함

IIS가 클라이언트 인증서를 받아들이도록 구성하려면, IIS 관리자에서 다음의 과정들을 수행합니다:

  1. 트리 뷰에서 설정하고자 하는 사이트의 노드를 클릭합니다.
  2. 메인 패인에서 SSL 설정(SSL Settings) 기능을 더블 클릭합니다.
  3. 클라이언트 인증서(Client Certificates) 항목에서 다음 중 한 가지 옵션을 선택합니다:
    • 수락(Accept): 클라이언트가 인증서를 제공하는 경우, IIS에서 이를 받아들이지만 필수로 요구하지는 않습니다.
    • 필요(Require): 클라이언트 인증서를 필수로 요구합니다. (이 옵션을 활성화시키려면 SSL 필요(Require SSL) 항목도 체크해야 합니다.)

    역주: 사이트에 HTTPS 바인딩을 추가해야만 SSL 설정(SSL Settings) 기능 내의 항목들이 활성화됩니다.

또는, ApplicationHost.config 파일을 직접 편집해서 이 옵션들을 설정할 수도 있습니다:

<system.webServer>
  <security>
    <access sslFlags="Ssl, SslNegotiateCert" />
    <!-- To require a client cert: -->
    <!-- <access sslFlags="Ssl, SslRequireCert" /> -->
  </security>
</system.webServer>

이 설정에서 SslNegotiateCert 플래그는 IIS가 클라이언트로부터 인증서를 받아들이지만, 필수로 요구하지는 않도록 지정합니다 (IIS 관리자의 수락(Accept) 옵션과 동일합니다). 반면, 인증서를 필수로 요구하려면 SslRequireCert 플래그를 설정합니다. 로컬 테스트를 위해서 이 옵션들을 "Documents\IISExpress\config"에 위치한 로컬 applicationhost.Config 파일에 설정해서 IIS 익스프레스에 적용할 수도 있습니다. (역주: 파일 탐색기의 경로 창에 %USERPROFILE%\Documents\IISExpress\config를 입력합니다.)

테스트 용 클라이언트 인증서 생성하기

직접 MakeCert.exe를 사용해서 테스트 용 클라이언트 인증서를 생성할 수 있습니다. 먼저, 테스트 루트 인증기관을 생성합니다:

makecert.exe -n "CN=Development CA" -r -sv TempCA.pvk TempCA.cer

이 명령을 수행하면 MakeCert 프로그램이 개인 키의 비밀번호를 입력하도록 프롬프트를 출력합니다.

그런 다음, 다음과 같이 인증서를 테스트 서버의 신뢰할 수 있는 루트 인증 기관(Trusted Root Certification Authorities) 저장소에 추가합니다:

  1. MMC를 실행합니다.
  2. 파일(File) 메뉴에서 스냅인 추가/제거(Add/Remove Snap-In)를 선택합니다.
  3. 인증서(Certificate) 스냅인을 선택해서 추가하고, 마법사에서 컴퓨터 계정(Computer Account) 옵션을 선택합니다.
  4. 로컬 컴퓨터(Local computer) 옵션을 선택한 다음 마법사를 완료합니다.
  5. 좌측 트리 뷰에서 신뢰할 수 있는 루트 인증 기관(Trusted Root Certification Authorities) 노드를 선택 및 확장합니다.
  6. 동작(Action) 메뉴에서 모든 작업(All Tasks)을 선택한 다음, 가져오기(Import)를 클릭해서 인증서 가져오기 마법사(Certificate Import Wizard)를 시작합니다.
  7. 방금 생성한 TempCA.cer 인증서 파일을 찾아서 선택합니다.
  8. 지시에 따라 마법사를 완료합니다.

역주: 이 과정을 원문의 지시대로 따라해보면 실제 상황과 맞지 않는 경우를 접하게 됩니다. 원문의 내용이 다소 부실한 편이어서 본 번역문에서는 일부 내용을 조정했습니다. 다만, 전체적인 맥락을 파악하는 데에는 무리가 없으므로 참고하시기 바랍니다.

이제 첫 번째 인증서로 서명된 클라이언트 인증서를 생성합니다:

makecert.exe -pe -ss My -sr CurrentUser -a sha1 -sky exchange -n "CN=name" -eku 1.3.6.1.5.5.7.3.2 -sk SignedByCA -ic TempCA.cer -iv TempCA.pvk

Web API에서 클라이언트 인증서 사용하기

서버 측에서는 요청 메시지에 대해 GetClientCertificate 메서드를 호출해서 클라이언트 인증서를 얻을 수 있습니다. 이 메서드는 클라이언트 인증서가 존재하지 않으면 null을 반환합니다. 반면, 클라이언트 인증서가 존재하면 X509Certificate2 인스턴스를 반환합니다. 이 개체를 이용해서 발급자나 주체 같은 인증서 정보를 알아낼 수 있습니다. 그런 다음, 이 정보들을 이용해서 인증을 수행하거나 권한을 부여하면 됩니다.

X509Certificate2 cert = Request.GetClientCertificate();
string issuer = cert.Issuer;
string subject = cert.Subject;