Desenvolvimento - C#

WCF Partial Trust

Uma das configurações mais importantes que se deve realizar em uma aplicação é a segurança, mais precisamente, que tipo de permissão devemos conceder à mesma para que ela possa ser executada...

por Israel Aéce



function doClick(index, numTabs, id) { document.all("tab" + id, index).className = "tab"; for (var i=1; i

WCF Partial Trust - [ Download ]


Uma das configurações mais importantes que se deve realizar em uma aplicação é a segurança, mais precisamente, que tipo de permissão devemos conceder à mesma para que ela possa ser executada. O tipo de permissão que me refiro aqui não tem a ver com a identidade do usuário, mas sim as permissões que o código (Assembly) tem para acessar recursos da máquina onde o mesmo está sendo executado.

Esse tipo de configuração foi introduzida desde a primeira versão do .NET Framework e é chamada de Code Access Security - CAS. Baseada no conceito de permissões, onde cada uma delas mapeia para um recurso (Message Queue, File System, SQL Server, etc.) da máquina, são através destas permissões que dizemos ao Runtime Security Policy (de forma declarativa ou imperativa), quais direitos nosso código tem de executar, ou melhor, a quais recursos ele terá acesso.

Se você cria qualquer aplicação .NET e não altera nenhuma configuração de segurança, ele será executado em Full Trust, ou seja, terá acesso irrestrito a qualquer recurso da máquina onde está atualmente sendo executado. Apesar disso ser muito comum, não é ideal. Uma premissa básica na segurança é jamais conceder direitos desnecessários a um código para desempenhar suas funções. Quando você opta por mudar a segurança padrão imposta pelo .NET, quer dizer que você está executando a aplicação em Partial Trust, ou seja, em um ambiente em que você não terá acesso a todos os recursos, mas sim, o essencial para a aplicação poder trabalhar.

Na primeira versão do WCF (Windows Communication Foundation) - .NET Framework 3.0 - ele não era suportado em ambientes que estavam sob Partial Trust, o que obrigava muitos clientes a conceder mais direitos do que o necessário para poder executar/invocar um serviço escrito em WCF. Depois de muitas requisições, a Microsoft decidiu afrouxar essa segurança com o lançamento do .NET Framework 3.5, permitindo (com várias restrições) que serviços sejam invocados a partir de um ambiente parcialmente confiável. Isso obrigou a Microsoft a decorar os assemblies System.ServiceModel.dll e System.ServiceModel.Web.dll com o atributo AllowPartiallyTrustedCallers que, como o nome diz, permite que o assembly seja invocado por aplicações que estão sendo executadas em um ambiente mais restrito.

Entre as limitações que o WCF 3.5 impõe, temos: permite somente os bindings BasicHttpBinding, WsHttpBinding (sem segurança ou com segurança a nível de transporte) e WebHttpBinding serem invocados a partir de uma aplicação que está sendo executada em ambiente parcialmente confiável; além disso, serviços WCF que estão rodando em aplicações de middle tier também podem invocar requisições para outros serviços, desde que tenha a sua respectiva WebPermisson, que concede direito de acesso a esse recurso. Todos os outros bindings, não HTTP, demandarão full trust de seus chamadores, obrigando-nos a conceder ao cliente mais direitos do que ele deveria ter para poder trabalhar. Para uma lista completa de todas as restrições, você pode consultar este link.

Mas e quando necessitamos referenciar em nossa aplicação parcialmente confiável, um serviço WCF que expõe apenas um endpoint com o binding definido como NetTcpBinding? Uma alternativa interessante é criar um proxy, isolando toda a chamada para este serviço. E no que consiste um proxy? Basicamente trata-se de uma DLL que conterá uma classe que servirá como um wrapper para a interface do serviço a ser acessado. Quando referenciamos o serviço diretamente na aplicação, automaticamente a IDE do Visual Studio se encarrega de criar a classe (também denominada proxy) para que possamos invocar os respectivos métodos do serviço localmente e que, durante a execução, será delegado ao serviço.

Para o nosso cenário isso não será a melhor saída. O que devemos fazer é utilizar o utilitário svcutil.exe que, entre suas utilidades, é capaz de gerar uma classe baseado no WSDL extraído do mesmo. A linha abaixo ilustra como devemos passar os parâmetros para o svcutil.exe para que o mesmo possa gerar a classe correspondente (executando a partir do prompt do Visual Studio .NET):

C:\>svcutil net.tcp://localhost:9000/Mex /out:C:\Proxy.cs
svcutil.exe

Uma vez que a classe é criada, criaremos um projeto do tipo Class Library e adicionaremos a classe recém criada, Proxy.cs, dentro deste projeto. Além disso, é também necessário fazer a referência para o assembly System.ServiceModel.dll. Depois deste processo, precisamos ainda fazer algumas configurações em nível de assembly; como essa DLL deverá ser consumida por um projeto que está sendo executado em um ambiente parcialmente confiável, adicionar no arquivo AssemblyInfo.cs o atributo AllowPartiallyTrustedCallers; finalmente, será necessário definir um Strong Name para essa DLL (veremos mais tarde, ainda neste artigo o motivo disso). O trecho de código abaixo ilustra como devemos proceder para definir o atributo APTCA:

using System.Security;

[assembly: AllowPartiallyTrustedCallers]
Imports System.Security

<Assembly: AllowPartiallyTrustedCallers>
C# VB.NET

Para finalizar, é necessário abrir o arquivo Proxy.cs e, no ínicio da classe que representa o serviço do lado do cliente (ClientBase), e especificar o atributo PermissionSetAttribute, assim como é mostrado abaixo:

using System.Security;
using System.Security.Permissions;

[PermissionSetAttribute(SecurityAction.Assert, Name = "FullTrust")]
public partial class Service1Client : System.ServiceModel.ClientBase<IService1>, IService1
{
    //Implementação
}
Imports System.Security
Imports System.Security.Permissions

<PermissionSetAttribute(SecurityAction.Assert, Name := "FullTrust")>
Public Partial Class Service1Client
    Inherits System.ServiceModel.ClientBase(Of IService1), 
    Implements IService1

    "Implementação
End Class
C# VB.NET

O atributo PermissionSetAttribute irá permitir a definição de uma determinada ação para uma permission set (conjunto de permissões) específica. No exemplo acima, estamos especificando a ação Assert (via enumerador SecurityAction) sob a permission set predefinida, que é a FullTrust. A utilização da ação/método Assert deve ser analisada com muito cuidado, pois é o mesmo que "Eu sei o que estou fazendo; confie em mim!", e isso garantirá que a permissão seja concedida ao chamador mesmo que ele não tenha privilégio para isso.

Finalmente, a DLL está pronta para ser utilizada mas se, neste momento, a mesma for referenciada na aplicação que está sendo executada em ambiente parcialmente confiável, uma exceção será atirada, dizendo que não é possível consumir um serviço via TCP nesta aplicação. Neste caso, necessitamos adicionar essa DLL no GAC, pois os componentes que lá residem já ganham Full Trust. É importante dizer que, mesmo assim, é necessário o código acima, pois o stack walk também verificará a aplicação Web que chama o componente e essa, por sua vez, não terá a permissão necessária e, consequentemente, a exceção será atirada. Esse conceito que utilizamos aqui também é conhecido como Sandboxing.

Importante: Apesar desta técnica funcionar, ela tem um ponto negativo: suprimindo a security demand, que é o processo de avaliação dos chamadores para se certificar que todos possuem tal permissão, permitirá que qualquer cliente que execute sob ambiente parcialmente confiável chame qualquer serviço WCF. Isso permitirá a um cliente que não tenha permissão de acesso a algum recurso, como acesso TCP, aplicar um bypass nesta limitação. A solução para esse problema é criar uma classe que herde diretamente da classe base ClientBase, concedendo as permissões específicas, dependendo do tipo de binding.

Conclusão: Felizmente o WCF permite na versão 3.5 do .NET Framework o consumo de serviços em ambiente parcialmente confiáveis. Alguns bindings podem ser consumidos sem a necessidade de alguma configuração adicional, pois são acessíveis em ambientes parcialmente confiáveis; já outros bindings não podem ser acessados diretamente, e necessitam de um passo adicional, que é a criação do proxy, explicado neste artigo.
Israel Aéce

Israel Aéce - Especialista em tecnologias de desenvolvimento Microsoft, atua como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. Como instrutor Microsoft, leciona sobre o desenvolvimento de aplicações .NET. É palestrante em diversos eventos Microsoft no Brasil e autor de diversos artigos que podem ser lidos a partir de seu site http://www.israelaece.com/. Possui as seguintes credenciais: MVP (Connected System Developer), MCP, MCAD, MCTS (Web, Windows, Distributed, ASP.NET 3.5, ADO.NET 3.5, Windows Forms 3.5 e WCF), MCPD (Web, Windows, Enterprise, ASP.NET 3.5 e Windows 3.5) e MCT.