Программирование безопасности WCF
В этом разделе описываются основные задачи программирования, используемые для создания безопасного приложения Windows Communication Foundation (WCF). В этом разделе рассматриваются только проверка подлинности, конфиденциальность и целостность, коллективно известные как безопасность передачи. Этот раздел не охватывает авторизацию (контроль доступа к ресурсам или службам); Сведения об авторизации см. в разделе "Авторизация".
Примечание.
Общие сведения о концепциях безопасности, особенно в отношении WCF, см. в наборе шаблонов и рекомендаций по MSDN в сценариях, шаблонах и рекомендациях по реализации для усовершенствований веб-служб (WSE) 3.0.
Программирование безопасности WCF основано на трех шагах, которые задаются следующим образом: режим безопасности, тип учетных данных клиента и значения учетных данных. Эти действия можно выполнить с помощью кода или конфигурации.
Задание режима безопасности
Ниже описаны общие действия по программированию с использованием режима безопасности в WCF:
Выберите одну из предопределенных привязок, отвечающих требованиям приложения. Список вариантов привязки см. в разделе "Предоставленные системой привязки". По умолчанию практически во всех привязках включены функции безопасности. Одним из исключений BasicHttpBinding является класс (с помощью конфигурации <, basicHttpBinding>).
Выбранная привязка определяет транспорт. Например, привязка WSHttpBinding использует протокол HTTP в качестве транспорта; привязка NetTcpBinding использует протокол TCP.
Выберите один из режимов безопасности привязки. Обратите внимание, что выбранная привязка определяет выбор доступных режимов. Например, привязка WSDualHttpBinding не позволяет обеспечить безопасность транспорта (это изменить нельзя). Аналогично, привязки MsmqIntegrationBinding и NetNamedPipeBinding не обеспечивают безопасность сообщений.
Доступны три варианта.
Transport
Безопасность транспорта зависит от механизма, используемого в выбранной привязке. Например, при использовании привязки
WSHttpBinding
в качестве механизма безопасности выступает протокол SSL (который также служит механизмом для протокола HTTPS). Основное преимущество безопасности транспорта заключается в обеспечении большой пропускной способности независимо от используемого типа транспорта. Однако имеются два ограничения. Первое ограничение - транспортный механизм определяет тип учетных данных, используемых для проверки подлинности пользователя. Этот недостаток проявляется, только если служба взаимодействует с другими службами, которым требуются другие типы учетных данных. Второе ограничение заключается в том, что безопасность применяется не на уровне сообщений, поэтому безопасность реализуется последовательным, а не сквозным способом. Это ограничение представляет проблему только в том случае, если на пути сообщения между клиентом и службой имеются посредники. Дополнительные сведения о том, какой транспорт следует использовать, см. в разделе "Выбор транспорта". Дополнительные сведения об использовании транспортной безопасности см. в разделе "Обзор безопасности транспорта".Message
Под безопасностью сообщений понимается наличие в каждом сообщении необходимых заголовок и данных для обеспечения безопасности сообщения. Поскольку состав заголовков не является фиксированным, можно включать любое количество учетных данных. Это становится важным в случае взаимодействия с другими службами, которым требуются учетные данные определенного типа, которые невозможно предоставить с помощью транспортного механизма, или если сообщение необходимо использовать для нескольких служб, которым требуются различные учетные данные.
Дополнительные сведения см. в разделе "Безопасность сообщений".
TransportWithMessageCredential
В этом случае транспортный уровень используется для защиты передачи сообщений. При этом каждое сообщение включает расширенные учетные данные, необходимые другим службам. Этот способ сочетает повышение производительности механизма безопасности транспорта с наличием различных учетных данных механизма безопасности сообщений. Его можно использовать со следующими привязками: BasicHttpBinding, WSFederationHttpBinding, NetPeerTcpBinding и WSHttpBinding.
Если принято решение использовать безопасность транспорта для протокола HTTP (т.е. протокол HTTPS), необходимо настроить узел с сертификатом SSL и включить SSL для порта. Дополнительные сведения см. в разделе "Безопасность транспорта HTTP".
Если используется привязка WSHttpBinding и при этом не требуется устанавливать безопасный сеанс, следует присвоить свойству EstablishSecurityContext значение
false
.Безопасный сеанс создается, когда клиент и служба создают канал с использованием симметричного ключа (клиент и служба используют один и тот же ключ в течение всего диалога вплоть до его завершения).
Задание типа учетных данных клиента
Выберите необходимый тип учетных данных клиента. Дополнительные сведения см. в разделе "Выбор типа учетных данных". Доступны следующие типы учетных данных клиента:
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
Тип учетных данных задается с учетом выбранного режима. Например, если выбрана привязка wsHttpBinding
и задан режим Message, необходимо также присвоить атрибуту clientCredentialType
элемента Message одно из следующих значений: 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: {0}", ce.Message);
Console.WriteLine();
}
catch (System.Exception exc)
{
Console.WriteLine("An unforeseen error occurred: {0}", 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 @ {0}", 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()