Como já havia mencionado aqui na seção de segurança, uma boa prática é não permitir que aplicações Web sejam executadas em FullTrust (padrão). Esse nível concede a aplicação Web, acesso a todos os recursos do servidor, tais como, acesso a sistema de arquivos, banco de dados, acesso ao Registry, execução de código não gerenciado, etc.. São permissões que, muitas vezes, não são necessárias e, se concedidas à alguém com más intenções, poderá comprometer a segurança do servidor e da rede.
Para evitar isso, voce pode configurar este nível de segurança tanto no arquivo Web.Config da aplicação ou, se desejar, no arquivo Web.Config que está a nível de servidor. Se optar por alterar o segundo, todas as aplicações ASP.NET que correm naquele servidor, utilizarão esse nível. E ainda, neste segundo (servidor), é importante que voce também altere o atributo allowOverride para false, justamente para que isso não possa ser sobrescrito pelas aplicações. Abaixo um exemplo de como alterar o nível de segurança apenas em uma aplicação:
<configuration>
<system.web>
<trust level=”Medium” />
</system.web>
</configuration>
Com isso, voce terá restrições ao rodar o seu código. Um exemplo é com relação ao sistema de arquivos. Com o nível Medium, voce apenas poderá ler e escrever arquivos no diretório da aplicação e nada mais. Se desejar ler ou salvar um arquivo em C:Temp uma exceção será atirada.
Uma vez negado o acesso a todo o sistema de arquivos, pode ser necessário que a aplicação necessite acessar o diretório C:Temp. Com essa necessidade, temos duas técnicas que podemos recorrer para conceder o acesso que acabamos de negar. Essas técnicas estão descritas abaixo:
-
Modificar o arquivo de segurança: essa técnica consiste na alteração do arquivo de configuração que está relacionado com o nível de segurança especificado. Como definimos Medium, as permissões que são concedidas, estão contidas dentro do arquivo web_mediumtrust.config, no diretório de configuração do .NET Framework 2.0.
-
Utilizar a técnica de SandBoxing: SandBoxing (tema do post) consiste em voce fatorar, ou melhor, isolar o seu código em um outro Assembly, concedendo a este, permissões específicas para o que ele deseja fazer (no nosso caso é ler/salvar arquivos no diretório C:Temp).
O isolamento consiste basicamente em gerar uma DLL (projeto Class Library) e assiná-la com um strong-name. Uma vez criada essa DLL voce deve adicioná-la no GAC que, por padrão, Assemblies lá colocados ganham FullTrust. Se o GAC não estiver acessível, então voce deverá colocar o Assembly no diretório Bin da aplicação e ainda mudar o arquivo de configuração do nível de segurança, concendendo mais privilégios para o Assembly, baseando-se no publicador ou strong-name. É importante dizer que para ambos os casos é necessário que voce tenha privilégios administrativos no servidor.
Ainda há mais um detalhe na criação da DLL. É extremamente necessário que voce defina o atributo AllowPartiallyTrustedCallers (System.Security) no arquivo AssemblyInfo. Esse atributo permitirá que o componente seja chamado através de aplicações (código) parcialmente confiáveis (partial trust).
Finalmente voce executa a aplicação Web, fazendo chamada para este componente e, quando tenta criar um arquivo texto no C:Temp, uma exceção do tipo SecurityException é atirada dizendo que voce – ainda – não tem permissões para isso (FileIOPermission). Isso ocorre justamente porque, momentos antes que o componente vai salvar o arquivo no disco, ele verifica as permissões de toda a stack; esse processo é chamado do stack walk e é onde ele percorre todas as chamadas para ver se todo mundo possui a permissão necessária para efetuar a tarefa.
No nosso caso, como adicionamos o componente no GAC, o componente possui a permissão, pois é atribuído a ele FullTrust; mas como o stack walk também verificará a aplicação Web que chama o componente, essa por sua vez, não terá a permissão necessária e, consequentemente, a exceção será atirada. Para permitir que tudo corra bem, então é necessário que voce modifique a stack, aplicando um Assert (cuidado com esse método) a permissão que está sendo requisitada. Esse método apenas verificará se o componente tem permissão, não percorrendo todos os chamadores. Sendo assim, o código do componente tem uma ligeira mudança:
public void WriteFile(string file, string content)
{
new FileIOPermission(FileIOPermissionAccess.AllAccess, file).Assert();
using (StreamWriter sw = new StreamWriter(file))
sw.Write(content);
}
Obviamente que isso é apenas um exemplo de teste. No mundo real, isso é bastante útil, já que muitas pessoas não se preocupam, e sempre deixam a configuração padrão do .NET que, em muitos casos, não é necessária e, neste caso, pode comprometer a segurança do servidor, principalmente, se ele for público.