Programmazione della sicurezza WCF
In questo argomento vengono descritte le attività di programmazione fondamentali usate per creare un'applicazione Windows Communication Foundation (WCF) sicura. Questo argomento illustra solo l'autenticazione, la riservatezza e l'integrità, note collettivamente come trasferire la sicurezza. Questo argomento non tratta l'autorizzazione (il controllo dell'accesso alle risorse o ai servizi); per informazioni sull'autorizzazione, vedere autorizzazione .
Nota
Per un'introduzione importante ai concetti di sicurezza, in particolare per quanto riguarda WCF, vedere il set di modelli e esercitazioni sulle procedure su MSDN all'indirizzo Scenario, Modelli e Linee guida all'implementazione per i miglioramenti dei servizi Web (WSE) 3.0.
La programmazione della sicurezza WCF si basa su tre passaggi, ovvero la modalità di sicurezza, un tipo di credenziale client e i valori delle credenziali. È possibile eseguire questi passaggi tramite codice o configurazione.
Impostazione della modalità di sicurezza
Di seguito vengono illustrati i passaggi generali per la programmazione con la modalità di sicurezza in WCF:
Selezionare una delle associazioni predefinite appropriate per i requisiti dell'applicazione. Per un elenco delle opzioni di associazione, vedere binding System-Provided. Per impostazione predefinita, quasi tutte le associazioni hanno la sicurezza abilitata. L'unica eccezione è la classe BasicHttpBinding (usando la configurazione, l'<basicHttpBinding>).
La selezione del vincolo determina il tipo di trasporto. Ad esempio, WSHttpBinding usa HTTP come trasporto; NetTcpBinding usa TCP.
Selezionare una delle modalità di sicurezza per il collegamento. Si noti che il vincolo selezionato determina le modalità disponibili. Ad esempio, il WSDualHttpBinding non consente la sicurezza del trasporto (non è un'opzione). Analogamente, né il MsmqIntegrationBinding né il NetNamedPipeBinding consente la sicurezza dei messaggi.
Sono disponibili tre opzioni:
Transport
La sicurezza del trasporto dipende dal meccanismo utilizzato dal binding che hai selezionato. Ad esempio, se si usa
WSHttpBinding
, il meccanismo di sicurezza è Secure Sockets Layer (SSL) (anche il meccanismo per il protocollo HTTPS). In generale, il vantaggio principale della sicurezza del trasporto è che offre una buona velocità effettiva indipendentemente dal trasporto in uso. Tuttavia, presenta due limitazioni: la prima è che il meccanismo di trasporto determina il tipo di credenziale usato per autenticare un utente. Questo è uno svantaggio solo se un servizio deve interagire con altri servizi che richiedono tipi diversi di credenziali. Il secondo è che, poiché la sicurezza non viene applicata a livello di messaggio, la sicurezza è implementata in modo salto per salto anziché end-to-end. Questa seconda limitazione è un problema solo se il percorso del messaggio tra client e servizio include intermediari. Per ulteriori informazioni sul trasporto da utilizzare, vedere Scelta di un trasporto. Per altre informazioni sull'uso della sicurezza del trasporto, vedere Transport Security Overview.Message
La sicurezza dei messaggi significa che ogni messaggio include le intestazioni e i dati necessari per proteggere il messaggio. Poiché la composizione delle intestazioni varia, è possibile includere un numero qualsiasi di credenziali. Questo fattore diventa un fattore se si interagisce con altri servizi che richiedono un tipo di credenziale specifico che un meccanismo di trasporto non può fornire o se il messaggio deve essere usato con più di un servizio, in cui ogni servizio richiede un tipo di credenziale diverso.
Per altre informazioni, vedere Message Security.
TransportWithMessageCredential
Questa scelta usa il livello di trasporto per proteggere il trasferimento dei messaggi, mentre ogni messaggio include le credenziali avanzate necessarie per altri servizi. Questo combina il vantaggio delle prestazioni della sicurezza del trasporto con i vantaggi avanzati delle credenziali della sicurezza dei messaggi. È disponibile con le associazioni seguenti: BasicHttpBinding, WSFederationHttpBinding, NetPeerTcpBindinge WSHttpBinding.
Se si decide di usare la sicurezza del trasporto per HTTP (in altre parole, HTTPS), è necessario configurare l'host con un certificato SSL e abilitare SSL su una porta. Per altre informazioni, vedere HTTP Transport Security.
Se si usa il WSHttpBinding e non è necessario stabilire una sessione protetta, impostare la proprietà EstablishSecurityContext su
false
.Una sessione sicura si verifica quando un client e un servizio creano un canale usando una chiave simmetrica (sia il client che il server usano la stessa chiave per la lunghezza di una conversazione, fino alla chiusura della finestra di dialogo).
Impostazione del tipo di credenziale client
Selezionare un tipo di credenziale client in base alle esigenze. Per altre informazioni, vedere Selezione di un tipo di credenziale. Sono disponibili i tipi di credenziali client seguenti:
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
A seconda della modalità impostata, è necessario impostare il tipo di credenziale. Ad esempio, se è stata selezionata la wsHttpBinding
e la modalità è impostata su "Message", è anche possibile impostare l'attributo clientCredentialType
dell'elemento Message su uno dei valori seguenti: None
, Windows
, UserName
, Certificate
e IssuedToken
, come illustrato nell'esempio di configurazione seguente.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="myBinding">
<security mode="Message"/>
<message clientCredentialType="Windows"/>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
Oppure nel codice:
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
Impostazione dei valori delle credenziali del servizio
Dopo aver selezionato un tipo di credenziale client, è necessario impostare le credenziali effettive per il servizio e il client da usare. Nel servizio le credenziali vengono impostate usando la classe ServiceCredentials e restituite dalla proprietà Credentials della classe ServiceHostBase. L'associazione in uso implica il tipo di credenziale del servizio, la modalità di sicurezza scelta e il tipo di credenziale client. Il codice seguente imposta un certificato per le credenziali del servizio.
// 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
Impostazione dei valori delle credenziali client
Nel client, imposta i valori delle credenziali del client utilizzando la classe ClientCredentials e quelli restituiti dalla proprietà ClientCredentials della classe ClientBase<TChannel>. Il codice seguente imposta un certificato come credenziale in un client usando il protocollo 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()