Categories
개발(Development)

[.NET] 2-way SSL 환경에서 WebService 호출하기

2-way SSL이란, 일반적으로 Server 쪽 인증서만으로 SSL 연결을 하는 것과는 달리, Client 쪽에서도 인증서를 보내 서로 인증을 하는 환경을 말한다. 때문에 서로 데이터를 주고 받기 위해서는 Server 인증서, Client 인증서 두 개가 각각 필요하다.

2-way SSL
2-way SSL (출처: codeproject)

이 글에서는 일단 Client 인증서를 사용해서 Server 쪽에 Web Service API를 호출하는 것까지, 사용했던 방식을 정리해보고자 한다.

1. 인증서 설정

우선 Client 인증서가 필요하고, 해당 인증서를 Server 쪽에 등록하여 인증에 사용할 수 있도록 구성해야한다. 이 부분은 Server쪽 업체쪽에서 Client 인증서도 만들어 보내줬기 때문에 자세한 설명은 힘들다. 어쨌든 Client 인증서를 컴퓨터에 설치한 뒤, 브라우저를 열어 해당 서버에 잘 접속이 되는지를 확인해본다. 아마도 접속시 어떤 인증서를 사용할 것인지 물어보는 확인창이 열릴 것이고, 인증서 선택 후 페이지가 제대로 나오면 인증서에는 문제가 없는 것이다.
이제부터는 API 에서 사용하기 위해 설정하는 방법이다.

  1. [시작]-[실행]-mmc 를 입력하여 Microsoft Management Console 실행
  2. [파일]-[스냅인 추가/제거] 선택
  3. [인증서]를 선택하고 [추가] 버튼을 누른 뒤, [컴퓨터 계정]-[로컬 컴퓨터]를 선택한다.
    mmc_certificates
  4. [개인용]에서 오른쪽 클릭 후 [모든 작업]-[가져오기] 선택
  5. 찾아보기를 누른 후 파일형식을 [개인정보교환(*.pfx, *.p12)]로 바꾼 뒤, 위에서 설치했던 인증서 경로를 지정한다. (필자의 경우 client 인증에 사용되는 인증서 형식이 p12였다)
  6. 비밀번호를 물어본다면 입력해주고, 기본 설정대로 [다음]을 눌러 [마침]이 나올 때까지 완료해 준다.
  7. 인증서가 추가되었다면, 이제 IIS에서 접근할 수 있도록 권한을 열어주어야 한다. 추가된 인증서를 오른쪽 클릭하고 [모든 작업]-[개인 키 관리]를 선택한다.
  8. [그룹 또는 사용자 이름]에서 [추가]를 클릭
  9. 찾을 위치에서 범위를 컴퓨터 전체로 지정하고, 선택할 개체 이름에는 “IIS AppPool\DefaultAppPool”을 넣어 추가해준다. 이름 확인을 눌러주었을 때 DefaultAppPool 로 바뀐다면 제대로 된 것이다.(*IIS에서 인증서가 필요한 응용 프로그램 풀 이름을 확인하자. 여기서는 DefaultAppPool에 서비스가 올라가 있었다.)
  10. 이로써 MMC에서 설정은 끝났다.

2. 2-way SSL 환경에서 서비스 중인 WebService의 WSDL 등록

서버쪽 업체에서는 .NET 2.0 SOAP Web Service를 통해 API를 제공하고 있었다. 웹 참조 추가를 통해 WSDL을 등록해주면 해당 서비스가 제공하는 API를 이용할 수 있다. 일반적인 웹 참조 추가는 아래와 같은 순서로 이루어진다.

  1. 솔루션 탐색기의 [참조]에서 오른쪽 클릭하여 [서비스 참조 추가]를 선택(VS2010 기준)
  2. 왼쪽 아래의 [고급] 버튼을 누르고, 다음 화면에서 [웹 참조 추가]를 누른다.
  3. URL에 WebService의 주소를 넣어주면, 자동으로 ‘이 URL에서 찾은 웹 서비스’에 해당 서비스 이름이 노출된다.
  4. 사용하려는 이름을 지정하고 [참조 추가]를 누른다.

그런데 2-way SSL 환경에서 서비스 중인 URL을 입력하였더니, 웹 서비스의 metadata를 불러올 수 없는 오류가 발생하였다.

‘https://xxx.xxx.com/aaa.asmx’을(를) 다운로드하는 동안 오류가 발생했습니다.
HTTP 상태 403: Forbidden(으)로 인해 요청하지 못했습니다.
‘https://xxx.xxx.com/aaa.asmx/$metadata’을(를) 다운로드하는 동안 오류가 발생했습니다.
요청이 실패했습니다(HTTP 상태 403).

이때 아래와 같이 해결할 수 있다.
– 해결방법 1 – WSDL 로컬에 저장하여 참조하기

  1. 브라우저에서 웹 서비스의 WSDL 주소로 접근하여 정보를 확인한다.
  2. [파일]-[다른 이름으로 저장]을 통해 wsdl 파일을 로컬에 저장한다.
  3. VS에서 웹 참조 추가를 통해 URL을 입력하는 화면까지 진행한다.
  4. URL 입력 창에 아래처럼 경로를 넣어준다.
    file://c:\temp\aaa.wsdl
  5. 서비스 이름을 확인한 뒤, 웹 참조 이름을 지정하고 [참조 추가]를 누른다.

– 해결방법 2 – svcutil.exe 사용하기
해결방법 1로 로컬에서는 문제 없이 서비스호출이 됐지만, 실제 서비스를 올리려고 하면 XmlSerializer 참조 오류가 발생했다. 결국 웹 참조 대신 wsdl -> class 변환 툴을 활용하여 처리하는 방식으로 변경하였다.

  1. Visual Studio 명령 프롬프트 실행(글 작성시는 VS2010 환경)
  2. svcutil.exe <wsdl 파일 경로> /language:<사용할 언어>
    ex) svcutil c:\temp\aaa.wsdl /language:C#
  3. 성공적으로 수행되면 클래스 파일과 output.config 파일이 생성된다.
  4. 클래스 파일을 프로젝트에 추가하고, output.config 파일의 내용은 web.config 파일에 추가하여 준다.
    output.config 에는 웹 서비스 호출에 사용될 endpoint 주소 등이 들어가 있다.
  5. 4에서 붙여넣은 내용 중에, <security> 항목 아래에 <transport clientCredentialType=”None”> 이란 항목이 있다. Client 인증서를 사용할 것이기 때문에, “None”을 “Certificate”로 바꿔준다.

3. 인증서와 함께 서비스 호출

이제는 Client 인증서와 함께 서비스를 호출하는 부분이다. 이 부분은 소스에서 몇 줄만 추가해주면 된다.
– 해결방법 1의 경우

// 웹서비스 객체 생성
MyWebService.Service1 s1 = new MyWebService.Service1();
// 로컬 컴퓨터의 인증서 보관함에 접근한다. 위에서 인증서를 로컬 컴퓨터에 저장했음을 기억하자.
X509Store localStore = new X509Store(StoreLocation.LocalMachine);
localStore.Open(OpenFlags.ReadOnly);
// 로컬 보관함에서 사용할 인증서를 찾는다. 여기서는 이름을 사용했다.
X509Certificate2Collection certs = localStore.Certificates.Find(X509FindType.FindBySubjectName, "MyClientCertName", true);
if( certs.Count > 0 ) {
    X509Certificate2 cert = certs[0];
    s1.ClientCertificates.Add(cert); // 인증서를 웹서비스 객체의 Client 인증서에 추가한다.
}
// 서비스 호출
s1.method1(param1, param2);

– 해결방법 2의 경우

// 웹서비스 객체 생성
MyWebService.Service1 s1 = new MyWebService.Service1();
// 사용할 인증서를 찾아서 객체에 추가해준다.
s1.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "MyClientCertName");
// 서비스 호출
s1.method1(param1, param2);

이제 실제로 프로그램을 실행해 서비스 호출 결과가 잘 오는지 확인하면 된다.