이 항목에서는 보안 WCF(Windows Communication Foundation) 애플리케이션을 만드는 데 사용되는 기본 프로그래밍 작업에 대해 설명합니다. 이 항목에서는 인증, 기밀성 및 무결성(총칭하여 전송 보안이라고 함)만 다룹니다. 이 항목에서는 권한 부여(리소스 또는 서비스에 대한 액세스 제어)를 다루지 않습니다. 권한 부여에 대한 자세한 내용은 권한 부여를 참조하세요.
비고
특히 WCF와 관련하여 보안 개념에 대한 유용한 소개는 WSE(Web Services Enhancements) 3.0의 시나리오, 패턴 및 구현 지침에서 MSDN에 대한 패턴 및 사례 자습서 집합을 참조하세요.
프로그래밍 WCF 보안은 보안 모드, 클라이언트 자격 증명 형식 및 자격 증명 값의 세 가지 단계를 설정합니다. 코드 또는 구성을 통해 이러한 단계를 수행할 수 있습니다.
보안 모드 설정
다음은 WCF에서 보안 모드로 프로그래밍하는 일반적인 단계를 설명합니다.
애플리케이션 요구 사항에 적합한 미리 정의된 바인딩 중 하나를 선택합니다. 바인딩 선택 항목 목록은 System-Provided 바인딩을 참조하세요. 기본적으로 거의 모든 바인딩은 보안을 사용하도록 설정되어 있습니다. 한 가지 예외는 BasicHttpBinding 클래스입니다 (구성을 사용한 <basicHttpBinding>).
선택한 바인딩에 따라 전송이 결정됩니다. 예를 들어 WSHttpBinding HTTP를 전송 NetTcpBinding 으로 사용하고 TCP를 사용합니다.
바인딩에 대한 보안 모드 중 하나를 선택합니다. 선택한 바인딩에 따라 사용 가능한 모드 선택 항목이 결정됩니다. 예를 들어 전송 보안은 WSDualHttpBinding 허용되지 않습니다(옵션이 아님). 마찬가지로 MsmqIntegrationBinding와 NetNamedPipeBinding 모두 메시지 보안을 허용하지 않습니다.
다음과 같은 세 가지 선택 옵션이 있습니다.
Transport
전송 보안은 선택한 바인딩에서 사용하는 메커니즘에 따라 달라집니다. 예를 들어 사용하는
WSHttpBinding
경우 보안 메커니즘은 SSL(Secure Sockets Layer)(HTTPS 프로토콜에 대한 메커니즘)입니다. 일반적으로 전송 보안의 주요 이점은 사용 중인 전송에 관계없이 좋은 처리량을 제공한다는 것입니다. 그러나 두 가지 제한 사항이 있습니다. 첫 번째는 전송 메커니즘이 사용자를 인증하는 데 사용되는 자격 증명 형식을 지시한다는 것입니다. 이는 서비스가 다른 유형의 자격 증명을 요구하는 다른 서비스와 상호 운용해야 하는 경우에만 단점입니다. 두 번째로, 보안이 메시지 수준에서 적용되지 않기 때문에, 보안이 종단 간으로가 아닌 홉 단위로 구현된다는 것입니다. 이 후자의 제한 사항은 클라이언트와 서비스 간의 메시지 경로에 중개자가 포함된 경우에만 문제가 될 수 있습니다. 사용할 전송에 대한 자세한 내용은 전송 선택을 참조하세요. 전송 보안 사용에 대한 자세한 내용은 전송 보안 개요를 참조하세요.Message
메시지 보안은 모든 메시지에 메시지 보안을 유지하는 데 필요한 헤더와 데이터가 포함되어 있음을 의미합니다. 헤더의 컴퍼지션은 다양하므로 원하는 수의 자격 증명을 포함할 수 있습니다. 이는 전송 메커니즘에서 제공할 수 없는 특정 자격 증명 형식을 요구하는 다른 서비스와 상호 운용하거나 각 서비스가 다른 자격 증명 형식을 요구하는 두 개 이상의 서비스와 함께 메시지를 사용해야 하는 경우에 영향을 줍니다.
자세한 내용은 메시지 보안을 참조하세요.
TransportWithMessageCredential
이 선택은 전송 계층을 사용하여 메시지 전송을 보호하는 반면, 모든 메시지에는 다른 서비스에 필요한 풍부한 자격 증명이 포함됩니다. 이는 전송 보안의 성능 이점과 메시지 보안의 풍부한 자격 증명 이점을 결합합니다. 다음 바인딩에서 사용할 수 있습니다. BasicHttpBinding, WSFederationHttpBinding, NetPeerTcpBinding및 WSHttpBinding.
HTTP에 대한 전송 보안(즉, HTTPS)을 사용하기로 결정한 경우 SSL 인증서를 사용하여 호스트를 구성하고 포트에서 SSL을 사용하도록 설정해야 합니다. 자세한 내용은 http 전송 보안 참조하세요.
WSHttpBinding을 사용 중이고 보안 세션을 설정할 필요가 없는 경우 EstablishSecurityContext 속성을
false
로 설정합니다.클라이언트와 서비스가 대칭 키를 사용하여 채널을 만들 때 보안 세션이 발생합니다(클라이언트와 서버 모두 대화가 닫혀 있을 때까지 대화 길이에 대해 동일한 키를 사용).
클라이언트 자격 증명 유형 설정
클라이언트 자격 증명 유형을 적절하게 선택합니다. 자세한 내용은 자격 증명 유형 선택을 참조하세요. 사용할 수 있는 클라이언트 자격 증명 형식은 다음과 같습니다.
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
모드를 설정하는 방법에 따라 자격 증명 유형을 설정해야 합니다. 예를 들어 wsHttpBinding
를 선택하고 모드를 "Message"로 설정한 경우, 다음 구성 예시와 같이 Message 요소의 clientCredentialType
속성을 None
, Windows
, UserName
, Certificate
, 또는 IssuedToken
중 하나로 설정할 수 있습니다.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="myBinding">
<security mode="Message"/>
<message clientCredentialType="Windows"/>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
코드에서 이렇게 합니다:
WSHttpBinding b = new WSHttpBinding();
b.Name = "myBinding";
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType=MessageCredentialType.Windows;
Dim b As New WSHttpBinding()
b.Name = "myBinding"
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
서비스 자격 증명 값 설정
클라이언트 자격 증명 유형을 선택하면 사용할 서비스와 클라이언트의 실제 자격 증명을 설정해야 합니다. 서비스에서 자격 증명은 ServiceCredentials 클래스를 사용하여 설정되며, 이후 Credentials 클래스의 ServiceHostBase 속성에 의해 반환됩니다. 사용 중인 바인딩은 서비스 자격 증명 유형, 선택한 보안 모드 및 클라이언트 자격 증명의 형식을 의미합니다. 다음 코드는 서비스 자격 증명에 대한 인증서를 설정합니다.
// Create the binding for an endpoint.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.Message;
// Create the ServiceHost for a calculator.
Uri baseUri = new Uri("net.tcp://MachineName/tcpBase");
Uri[] baseAddresses = new Uri[] { baseUri };
ServiceHost sh = new ServiceHost(typeof(Calculator), baseAddresses);
// Add an endpoint using the binding and a new address.
Type c = typeof(ICalculator);
sh.AddServiceEndpoint(c, b, "MyEndpoint");
// Set a certificate as the credential for the service.
sh.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindBySubjectName,
"client.com");
try
{
sh.Open();
Console.WriteLine("Listening....");
Console.ReadLine();
sh.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine($"A communication error occurred: {ce.Message}");
Console.WriteLine();
}
catch (System.Exception exc)
{
Console.WriteLine($"An unforeseen error occurred: {exc.Message}");
Console.ReadLine();
}
' Create the binding for an endpoint.
Dim b As New NetTcpBinding()
b.Security.Mode = SecurityMode.Message
' Create the ServiceHost for a calculator.
Dim baseUri As New Uri("net.tcp://MachineName/tcpBase")
Dim baseAddresses() As Uri = {baseUri}
Dim sh As New ServiceHost(GetType(Calculator), baseAddresses)
' Add an endpoint using the binding and a new address.
Dim c As Type = GetType(ICalculator)
sh.AddServiceEndpoint(c, b, "MyEndpoint")
' Set a certificate as the credential for the service.
sh.Credentials.ServiceCertificate.SetCertificate( _
StoreLocation.LocalMachine, _
StoreName.My, _
X509FindType.FindBySubjectName, _
"contoso.com")
Try
sh.Open()
Console.WriteLine("Listening....")
Console.ReadLine()
sh.Close()
Catch ce As CommunicationException
Console.WriteLine("A communication error occurred: {0}", ce.Message)
Console.WriteLine()
Catch exc As System.Exception
Console.WriteLine("An unforeseen error occurred: {0}", exc.Message)
Console.ReadLine()
End Try
클라이언트 자격 증명 값 설정
클라이언트에서는 ClientCredentials 클래스를 사용하여 클라이언트 자격 증명 값을 설정하고, ClientCredentials 클래스의 ClientBase<TChannel> 속성에서 이를 반환합니다. 다음 코드는 TCP 프로토콜을 사용하여 클라이언트에서 인증서를 자격 증명으로 설정합니다.
// Create a NetTcpBinding and set its security properties. The
// security mode is Message, and the client must be authenticated with
// Windows. Therefore the client must be on the same Windows ___domain.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
// Set a Type variable for use when constructing the endpoint.
Type c = typeof(ICalculator);
// Create a base address for the service.
Uri tcpBaseAddress =
new Uri("net.tcp://machineName.Domain.Contoso.com:8036/serviceName");
// The base address is in an array of URI objects.
Uri[] baseAddresses = new Uri[] { tcpBaseAddress };
// Create the ServiceHost with type and base addresses.
ServiceHost sh = new ServiceHost(typeof(CalculatorClient), baseAddresses);
// Add an endpoint to the service using the service type and binding.
sh.AddServiceEndpoint(c, b, "");
sh.Open();
string address = sh.Description.Endpoints[0].ListenUri.AbsoluteUri;
Console.WriteLine($"Listening @ {address}");
Console.WriteLine("Press enter to close the service");
Console.ReadLine();
' Create a NetTcpBinding and set its security properties. The
' security mode is Message, and the client must be authenticated with
' Windows. Therefore the client must be on the same Windows ___domain.
Dim b As New NetTcpBinding()
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
' Set a Type variable for use when constructing the endpoint.
Dim c As Type = GetType(ICalculator)
' Create a base address for the service.
Dim tcpBaseAddress As New Uri("net.tcp://machineName.Domain.Contoso.com:8036/serviceName")
' The base address is in an array of URI objects.
Dim baseAddresses() As Uri = {tcpBaseAddress}
' Create the ServiceHost with type and base addresses.
Dim sh As New ServiceHost(GetType(CalculatorClient), baseAddresses)
' Add an endpoint to the service using the service type and binding.
sh.AddServiceEndpoint(c, b, "")
sh.Open()
Dim address As String = sh.Description.Endpoints(0).ListenUri.AbsoluteUri
Console.WriteLine("Listening @ {0}", address)
Console.WriteLine("Press enter to close the service")
Console.ReadLine()