Programowanie zabezpieczeń WCF
W tym temacie opisano podstawowe zadania programistyczne używane do tworzenia bezpiecznej aplikacji windows Communication Foundation (WCF). W tym temacie opisano tylko uwierzytelnianie, poufność i integralność, nazywane zbiorczo zabezpieczeniami transferu. Ten temat nie obejmuje autoryzacji (kontrola dostępu do zasobów lub usług); Aby uzyskać informacje na temat autoryzacji, zobacz Autoryzacja.
Uwaga
Aby zapoznać się z cennym wprowadzeniem do pojęć dotyczących zabezpieczeń, szczególnie w odniesieniu do usługi WCF, zobacz zestaw wzorców i praktyk samouczków dotyczących witryny MSDN w temacie Scenariusze, wzorce i wskazówki dotyczące implementacji dla ulepszeń usług sieci Web (WSE) 3.0.
Zabezpieczenia programu WCF są oparte na trzech krokach ustawiania następujących kroków: tryb zabezpieczeń, typ poświadczeń klienta i wartości poświadczeń. Te kroki można wykonać za pomocą kodu lub konfiguracji.
Ustawianie trybu zabezpieczeń
Poniżej wyjaśniono ogólne kroki programowania w trybie zabezpieczeń w programie WCF:
Wybierz jedno ze wstępnie zdefiniowanych powiązań odpowiednich dla wymagań aplikacji. Aby uzyskać listę opcji powiązań, zobacz Powiązania dostarczone przez system. Domyślnie prawie każde powiązanie ma włączone zabezpieczenia. Jednym wyjątkiem jest BasicHttpBinding klasa (przy użyciu konfiguracji, podstawowaHttpBinding<>).
Wybrane powiązanie określa transport. Na przykład WSHttpBinding używa protokołu HTTP jako transportu; NetTcpBinding używa protokołu TCP.
Wybierz jeden z trybów zabezpieczeń dla powiązania. Pamiętaj, że wybrane powiązanie określa dostępne opcje trybu. Na przykład element WSDualHttpBinding nie zezwala na zabezpieczenia transportu (nie jest to opcja). Podobnie ani MsmqIntegrationBinding nie zezwalają na zabezpieczenia komunikatów NetNamedPipeBinding .
Dostępne są trzy opcje:
Transport
Bezpieczeństwo transportu zależy od mechanizmu, z którego korzysta wybrane powiązanie. Na przykład jeśli używasz
WSHttpBinding
mechanizmu zabezpieczeń to Secure Sockets Layer (SSL) (także mechanizm protokołu HTTPS). Ogólnie rzecz biorąc, główną zaletą zabezpieczeń transportu jest to, że zapewnia dobrą przepływność niezależnie od używanego transportu. Jednak ma dwa ograniczenia: po pierwsze mechanizm transportu określa typ poświadczeń używany do uwierzytelniania użytkownika. Jest to wadą tylko wtedy, gdy usługa musi współpracować z innymi usługami, które wymagają różnych typów poświadczeń. Drugim jest to, że ponieważ zabezpieczenia nie są stosowane na poziomie komunikatu, zabezpieczenia są implementowane w sposób przeskoku, a nie end-to-end. To ostatnie ograniczenie jest problemem tylko wtedy, gdy ścieżka komunikatu między klientem a usługą obejmuje pośredników. Aby uzyskać więcej informacji na temat transportu do użycia, zobacz Wybieranie transportu. Aby uzyskać więcej informacji na temat korzystania z zabezpieczeń transportu, zobacz Transport Security Overview (Omówienie zabezpieczeń transportu).Message
Bezpieczeństwo komunikatów oznacza, że każdy komunikat zawiera niezbędne nagłówki i dane, aby zapewnić bezpieczeństwo komunikatu. Ponieważ kompozycja nagłówków jest różna, można uwzględnić dowolną liczbę poświadczeń. Staje się to czynnikiem, jeśli współdziałasz z innymi usługami, które wymagają określonego typu poświadczeń, którego mechanizm transportu nie może dostarczyć, lub jeśli komunikat musi być używany z więcej niż jedną usługą, gdzie każda usługa wymaga innego typu poświadczeń.
Aby uzyskać więcej informacji, zobacz Zabezpieczenia komunikatów.
TransportWithMessageCredential
Ten wybór używa warstwy transportu do zabezpieczenia transferu komunikatów, podczas gdy każdy komunikat zawiera zaawansowane poświadczenia innych potrzebnych usług. Łączy to w sobie zaletę bezpieczeństwa transportu z zaawansowanymi poświadczeniami zabezpieczeń komunikatów. Jest to dostępne z następującymi powiązaniami: BasicHttpBinding, WSFederationHttpBinding, NetPeerTcpBindingi WSHttpBinding.
Jeśli zdecydujesz się używać zabezpieczeń transportu dla protokołu HTTP (innymi słowy https), musisz również skonfigurować hosta przy użyciu certyfikatu SSL i włączyć protokół SSL na porcie. Aby uzyskać więcej informacji, zobacz Zabezpieczenia transportu HTTP.
Jeśli używasz elementu WSHttpBinding i nie musisz ustanawiać bezpiecznej sesji, ustaw EstablishSecurityContext właściwość na
false
.Bezpieczna sesja odbywa się, gdy klient i usługa tworzą kanał przy użyciu klucza symetrycznego (zarówno klient, jak i serwer używają tego samego klucza dla długości konwersacji, dopóki okno dialogowe nie zostanie zamknięte).
Ustawianie typu poświadczeń klienta
Wybierz odpowiedni typ poświadczeń klienta. Aby uzyskać więcej informacji, zobacz Wybieranie typu poświadczeń. Dostępne są następujące typy poświadczeń klienta:
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
W zależności od sposobu ustawiania trybu należy ustawić typ poświadczeń. Jeśli na przykład wybrano wsHttpBinding
parametr i ustawisz tryb na "Komunikat", możesz również ustawić clientCredentialType
atrybut elementu Message na jedną z następujących wartości: None
, , Certificate
Windows
UserName
, i IssuedToken
, jak pokazano w poniższym przykładzie konfiguracji.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="myBinding">
<security mode="Message"/>
<message clientCredentialType="Windows"/>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
Lub w kodzie:
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
Ustawianie wartości poświadczeń usługi
Po wybraniu typu poświadczeń klienta należy ustawić rzeczywiste poświadczenia dla usługi i klienta do użycia. W usłudze poświadczenia są ustawiane przy użyciu ServiceCredentials klasy i zwracane przez Credentials właściwość ServiceHostBase klasy . Powiązanie używane oznacza typ poświadczeń usługi, wybrany tryb zabezpieczeń i typ poświadczeń klienta. Poniższy kod ustawia certyfikat dla poświadczeń usługi.
// 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
Ustawianie wartości poświadczeń klienta
Na kliencie ustaw wartości poświadczeń klienta przy użyciu ClientCredentials klasy i zwrócone ClientCredentials przez właściwość ClientBase<TChannel> klasy. Poniższy kod ustawia certyfikat jako poświadczenie na kliencie przy użyciu protokołu 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()