Você está protegido?  

Projeto e Distribuição Seguras de Aplicações Web com ASP.NET 2.0 e IIS 6.0 

Michael Volodarsky 

Partes deste artigo estão baseadas em uma versão pre-release do ASP.NET 2.0. Este texto está sujeito a mudanças. 

________________________________________ 

Este artigo discute:

  • Proteção de recursos e controle de acesso;
  • Autenticação e autorização;
  • Segurança no acesso a código no ASP.NET;
  • Auditoria de Aplicações.

Aplicações Web estão entre os serviços de computação mais comumente expostos na Internet, e representam um objeto convidativo para qualquer um que queira invadir sua rede e roubar informação sensível, mexer com seus dados, ou então comprometer o seu sistema. Garantir a segurança de uma aplicação Web é uma tarefa séria, e requer cuidados ao longo das fases de projeto, desenvolvimento, distribuição e operação. Não deveria ser visto como algo que pode ser inserido em uma aplicação existente, ou simplesmente atingido aplicando características de segurança de plataformas existentes. 

Mesmo quando desenvolvemos para uso dentro de uma plataforma relativamente segura, uma aplicação Web tem que seguir as melhores práticas de segurança da plataforma ao longo dos estágios de projeto, desenvolvimento e distribuição, para prover o nível máximo de proteção contra ataques. Para produzir aplicações Web seguras, este conhecimento específico da plataforma deveria ser combinado com práticas de projeto seguras, modelagem de análise de ameaças e testes de segurança contra infiltração. 

Este artigo discute as melhores práticas que permitem tirar proveito das características de segurança do ASP.NET 2.0 e do IIS 6.0 e construir e distribuir aplicações Web mais seguras. 

Projetando Aplicações Web Seguras

Princípios de projeto seguros normalmente baseiam-se em alguns princípios chave: assumir que qualquer entrada no sistema é maliciosa, reduzir a área de contato exposta do sistema, bloquear o sistema por padrão e usar defesa em profundidade em lugar de confiar em outras partes do sistema para proteção. Seguindo estes princípios gerais a partir da fase de projeto é fundamental ter certeza da melhor proteção possível para a aplicação. 

O modelo de análise de ameaças é usado para traçar o fluxo de dados dentro de um sistema e examinar os possíveis pontos de entrada para um que usuário malicioso possa explorar o acesso ao mesmo. A modelagem de ameaças é um exercício fundamental para mudar a perspectiva do ponto de vista de um projetista para o de um atacante, ajudando-o a descobrir os furos de segurança potenciais na aplicação. Para mais informações sobre modelagem de ameaças, veja Modelagem de Ameaças http://msdn.microsoft.com/security/securecode/threatmodeling/

Teste de Penetração de Segurança é outro nome para a invasão da sua própria aplicação - tentar invadir a aplicação diretamente e achar problemas antes que outros o façam por você. Podemos tentar forçar a aplicação até seus limites enviando dados inválidos ou o pior caso de dados possível. Podemos tentar também “enlouquecer” a aplicação usando o nosso conhecimento do funcionamento interno da mesma - neste caso, este conhecimento dá uma vantagem injusta sobre atacantes típicos, mas também pode revelar vulnerabilidades que estão profundamente inseridas dentro do código. Há uma variedade de ferramentas disponíveis que podem ajudar a fazer o teste de penetração. 

Protegendo Recursos

Normalmente, a primeira tarefa na distribuição de uma aplicação Web consiste em ter certeza de que não expõe recursos sensíveis que podem ser acessados por clientes anônimos na Internet. Se esta for uma aplicação intranet, isto é normalmente realizado mediante a certificação de que todos os clientes são autenticados com autenticação Windows® (veremos o controle de acesso mais adiante), e que a aplicação é protegida ao acesso externo por um firewall. Para uma aplicação Internet, este é um aspecto importante porque quase sempre precisa ter o mínimo de acessibilidade por usuários de Internet anônimos. Fora esta diferença, a seguinte orientação é, no entanto, igualmente aplicável para proteger recursos em aplicações Internet e intranet. 

Idealmente, é melhor ter certeza de o namespace Web da aplicação não contém qualquer arquivo que não pretendemos que seja servido ao cliente. Isto significa a remoção de todos estes arquivos da estrutura do diretório físico, começando com o mais alto diretório designado como uma aplicação Web ou diretório virtual na configuração IIS. Se o arquivo não estiver no namespace Web, não deveria ser acessível através de pedidos àquele namespace, a menos o código da aplicação abra diretamente o arquivo e sirva seus conteúdos. Se a aplicação acessar os dados programaticamente ou suportar arquivos durante sua execução, deveríamos colocá-los fora do namespace Web. 

Se não pudermos remover todos estes arquivos, devemos ter certeza de que o IIS não está configurado para servir estes arquivos a clientes Web. Isto deveria ser realizado mapeando as extensões aos arquivos protegidos do ASP.NET no processador de configuração  de mapeamento de script do IIS (veja Figura 1), e mapeando essas extensões subseqüentemente para o HttpForbiddenHandler na configuração  ASP.NET <HTTPHANDLERS> da aplicação ou diretório. Por padrão, o ASP.NET já bloqueia o acesso a várias extensões comuns de aplicações Web, incluindo .cs .java .mdb .mdf .vb e outros. 

Figure 1 Mapping XML Files to the ASP.NET ISAPI Extension  
Figura 1 Mapeamento de Arquivos XML para Extensões ISAPI ASP.NET

Configurando o Web.config como a seguir, impedimos que a extensão .xml seja servida, caso a extensão seja mapeada para o ASP.NET nesta esta aplicação:   
        <HTTPHANDLERS>
type="System.Web.HttpForbiddenHandler" />
         
Note que esta configuração gera uma resposta de erro "403 Forbbiden", com uma mensagem ASP.NET que comprova a existência deste arquivo. Podemos também usar o System.Web.HttpNotFoundHandler para mascarar a existência do arquivo e devolver uma resposta genérica 404.  

Se desinstalarmos o ASP.NET, o mapeamento do processador de script IIS será removido e as extensões não mapeadas serão processadas pelo manipulador de arquivo estático do IIS. Freqüentemente imaginamos que removendo uma entrada da extensão correspondente da configuração de mapeamento IIS MIME, impedirá que manipulador de arquivo estático sirva arquivos com aquela extensão. Na realidade, isto não é sempre verdadeiro, porque o manipulador de arquivo estático também levará em conta a configuração de mapeamento do registro MIME e ainda servirá a extensão se a entrada de registro estiver presente. Por causa disto, teríamos que ter certeza que ambos a configuração de Mapeamento do meta-base MIME e a chave de registro HKEY_CLASSES_ROOT, não contenham uma entrada de extensão proibida. Devido à complexidade de administração inerente, esta prática não é recomendada como uma maneira de garantir conteúdo. Se usarmos este método, também deveríamos ocultar os arquivos para proteção adicional, pois o manipulador de arquivo estático IIS, não servirá arquivos que tenham o atributo oculto.

Claro que esta orientação relativa ao manipulador de arquivo estático IIS, só se aplica a extensões que não são mapeadas para uma extensão de ISAPI no mapeamento da configuração do script IIS. Se a extensão é mapeada, então a extensão do script de mapeamento ISAPI do IIS correspondente, será responsável por controlar o acesso a pedidos que tenham aquela extensão. 

Podemos também tirar proveito das características de diretórios protegidos do ASP.NET 2.0. Por padrão, o ASP.NET 2.0 bloqueará o acesso a todas as URLs que contêm segmentos de diretório chamados App_Data, App_Code, App_Browsers, App_WebReferences, App_GlobalResources e App_LocalResources, em qualquer lugar da URL. O ASP.NET 1.1 e 2.0 também irão bloquear o acesso ao diretório /Bin. Este suporte está condicionado a ter o filtro de registro aspnet_filter.dll do ISAPI com o IIS, o qual é instalado por padrão durante a instalação do ASP.NET. Colocando o conteúdo nestes diretórios, podemos impedir o acesso de HTTP independentemente das extensões do arquivo que são pedidas. A Tabela 1 descreve os diretórios protegidos sob o ASP.NET 2.0. URLs que contêm outros segmentos App_*, inclusive o diretório App_Themes, não são bloqueados pelo ASP.NET. 

Tabela 1 Caminhos com Acesso Negado Via Requisições Diretas de HTTP no ASP.NET 2.0

Diretório

Descrição

/Bin

Contem assemblys gerenciados pela aplicação. Também bloqueados no ASP.NET 1.1.

/App_Code

Contém código de aplicação compilável.

/App_Data

Contém arquivos de dados da aplicação.

/App_LocalResources

Contém recursos do diretório local.

/App_GlobalResources

Contém recursos de aplicação globais.

/App_WebReferences

Contém referências Web geradas pelo Visual Web Developer.

/App_Browsers

Contém definições do navegador.

Controle de acesso

A maioria das aplicações Web provêem múltiplos níveis de acesso a dados e recursos, e precisamos garantir que os clientes receberão o acesso apropriado, baseado nas suas credenciais. O controle de acesso em aplicações Web, é controlado tipicamente em duas fases: autenticação e autorização. A autenticação determina a identidade do cliente que faz o pedido. A autorização determina se aquela identidade cliente, tem permissão para acessar um recurso particular. A Figura 2 ilustra as fases de segurança relevantes do processamento do pedido em requisições HTTP típicas na plataforma IIS/ASP.NET. 

Figure 3 Processing an HTTP Request  
Figura 2 Processando um Pedido HTTP

Há vários mecanismos “não usuário” de controle de acesso disponíveis, que podemos considerar para reduzir a área de ataque da aplicação. Estes mecanismos do IIS 6.0 incluem a lista de restrição de IP e a lista de restrições de extensão Web service. 

A lista de restrição de IP permite especificar os endereços de IP dos clientes que terão acesso permitido à aplicação. Podemos configurar IPs específicos e domínios, bem como subnets. Considere fazer isto, caso a aplicação for só intranet, ou se os clientes sempre acessam a aplicação em um endereço de IP ou domínio específico. Quando aplicável, deveríamos usá-lo como uma medida de defesa em profundidade junto com outros métodos de controle de acesso. 

A lista de restrições de extensão, permite definir globalmente a extensão ISAPI de arquivos DLL e a de arquivos CGI .exe, que podem ser executados no servidor. Por padrão, são proibidas todas as extensões desse tipo, e deveríamos habilitar só aquelas estritamente necessárias, deixando as outras desabilitadas. A instalação de produtos de terceiros pode habilitar componentes adicionais, Poderíamos assim, precisar desabilitá-los se não estivermos usando-os para servir conteúdo Web. 

Versões prévias do IIS, também se beneficiam do filtro ISAPI UrlScan, que provê validação de pedidos adicional e bloqueamento de entradas de risco. O IIS 6.0 sofreu reengenharia para prover maior segurança em relação às versões anteriores, e já não expõe vulnerabilidades que requeriam a proteção do UrlScan. Porém, se as exigências de segurança não estiverem cobertas pelas características providas por padrão no IIS 6.0, podemos querer continuar usando o UrlScan. A informação disponível em Determinando se Devemos Usar o UrlScan 2.5 com o IIS 6.0 -
http://msdn.microsoft.com/isapi/gomscom.asp?TARGET=/technet/security/tools/urlscan.mspx#EDAA
podem ajudar a decidirmos quanto ao uso ou não do UrlScan. 

Autenticação 

O IIS e o ASP.NET, disponibilizam juntos, os elementos fundamentais para construir mecanismos de controle de acesso, e o ASP.NET 2.0 se expande mais ainda para prover blocos de aplicação prontos, que podem ser usados para distribuir tais mecanismos rapidamente. 

A saída dos mecanismos de autenticação IIS sempre é uma identidade Windows que representa o usuário para quem o pedido está sendo feito. O IIS provê suporte embutido aos seguintes tipos de autenticação:
anonymous, Windows integrated, Basic, Digest, certificate mapping e Microsoft® Passport. A Tabela 2 ilustra quando os diferentes modos de autenticação são tipicamente usados. 

Tabela 2 Métodos de Autenticação

Método de Autenticação

Tipo de Aplicação

O Usuário deve ter Conta Windows

Comentários

Anonymous

Ambos

Não

Usado com esquemas de autenticação em nível de aplicação.

Integrated Windows

Intranet

Sim

Uso na Internet é possível mas não recomendado.

Basic

Internet ou intranet quando existirem limitações de confiança de domínio ou de firewall proibindo o uso de autenticação integrada Windows.

Sim

Senha enviada via texto aberto. Deve usar SSL para impedir a exposição da senha.

Digest

Internet

Sim

Requer Active Directory.

Certificate mapping

Internet

Sim

Requer a emissão de um certificado de cliente.

Passport

Internet

Não, mas tem que ter conta de Passaport

Requer afiliação via Passport.

Aplicações Intranet usarão a autenticação Windows Integrada, tipicamente para autenticar os clientes com suas contas de domínio. Alternativamente, podem usar autenticação de certificado, entretanto certificados são mais comuns na área da Internet. Aplicações Internet deveriam usar autenticação Básica de SSL ou autenticação Digest se os usuários têm contas Windows, ou autenticação anônima com um esquema de autenticação específico de aplicação caso não tenham contas Windows. 

Se a autenticação anônima não é habilitada para uma URL, então o IIS garantirá que o pedido seja autenticado ou rejeitará o pedido. Isto deveria ser usado como uma medida de defesa em profundidade, para aplicações que usam outros mecanismos de autenticação IIS (a maioria das aplicações intranet), para rejeitar completamente todos os usuários não autenticados, se nenhum acesso anônimo for desejado. 

O ASP.NET suporta três tipos de autenticação: Windows, Forms e Passport. A autenticação Windows simplesmente aceita a identidade Windows produzida durante a autenticação IIS. A autenticação Forms implementa um esquema de camada de autenticação, baseado em ingresso, a ser usado por aplicações ASP.NET que não associam contas Windows aos usuários (a autenticação Form deveria ser combinada com a opção autenticação IIS anônima). A autenticação Passport usa o esquema de autenticação Microsoft Passport. O esquema de autenticação para cada aplicação é especificado dentro do elemento de configuração <SYSTEM.WEB><AUTHENTICATION>, como mostrado aqui:   

Com autenticação Forms, quando o usuário tem acesso negado para um recurso que requer autenticação, será redirecionado para uma URL configurada que aponta para uma página de login. A página de login é uma página ASP.NET, personalizada, escrita pelo desenvolvedor da aplicação, que provê um modo do usuário fornecer credenciais. A página de login valida então as credenciais em uma área de armazenamento do usuário personalizada, como por exemplo um banco de dados SQL, e usa a classe System.Web.FormsAuthentication para emitir um ingresso de autenticação encriptado para o cliente. Este ingresso pode ser um cookie ou um blob especial, que amplia a URL (começando com o ASP.NET 1.1 Mobile Toolkit e o ASP.NET 2.0 - Caixa de Ferramentas Mobile ASP.NET 1.1 e ASP.NET 2.0). Em todo pedido subseqüente, o cliente apresenta este ingresso, e o mecanismo de autenticação Forms automaticamente o processa para gerar a identidade do usuário para o pedido.  

Com autenticação Forms, a complexidade de emitir e administrar o ingresso de autenticação é absorvida pelo framework do ASP.NET. Porém, ainda temos que escrever a chamada ao login e a implementação da área de armazenamento do usuário associada. O ASP.NET 2.0 simplifica o processo completo provendo dois componentes adicionais: o serviço Membership e o família de controles de Login. 

O serviço Membership, exposto pela classe System.Web.Security.Membership, provê uma abstração útil para criar, administrar e validar credenciais de usuário. Como muitas outras características ASP.NET 2.0, o provedor baseado em projeto permite que o serviço trabalhe com compatibilidade retroativa com uma variedade de armazenadores de dados (data stores), inclusive SQL Server™ e provedores do Active Directory® que são incluídos no framework do ASP.NET. Montar a sua própria implementação de banco de dados de usuário é tão fácil quanto a distribuição do schema de banco de dados Membership para a instância do SQL Server ou do SQL Server Express via ferramenta aspnet_regsql.exe, e configurando um SqlMembershipProvider - ou apenas usando o provedor padrão que automaticamente cria o banco de dados Membership SQL Server Express no diretório App_Data da aplicação por ocasião do primeiro acesso. 

O serviço Membership provê suporte para muitas funções de administração de usuário comum, inclusive hashing de senha, bloqueio de conta e login. Você pode descobrir mais sobre o serviço Membership no ASP.NET 2.0 Quickstart (Usando as APIs Membership e Gerente de Papéis - http://beta.asp.net/QuickStartv20/aspnet/doc/security/membership.aspx

Com o controle Login ASP.NET 2.0, o ponto crucial da criação de página login é simplificado mesmo mais adiante provendo um controle arrastar e soltar que implementa automaticamente qualquer funcionalidade de login de página trabalhando com as APIs de autenticação Membership e forms para validar as credenciais de usuário e criar o ingresso de autenticação em um logon bem sucedido. O controle Login provê funcionalidade flexível, inclusive funcionando com provedores Membership personalizados, executando reinicialização de consulta / resposta de senha, e fazendo validação credenciais personalizadas. Um conjunto de controles de suporte, inclusive controles LoginView e CreateUser, pode ser usado para suportar o resto da interface de administração de usuário (veja Usando os Controles de Login - http://beta.asp.net/QuickStartv20/aspnet/doc/security/login.aspx). 

Ao usar autenticação de aplicação personalizada com autenticação forms ou com o seu próprio mecanismo de autenticação, proteja suas chamadas de login e preferivelmente a aplicação inteira com Secure Socket Layer - SSL para impedir a revelação de credenciais de login e autenticação de ingressos (eu cobrirei a segurança de autenticação de ingresso com mais detalhe, mais adiante neste artigo.) Também, deveria exigir que seus usuários usassem senhas robustas. O serviço Membership provê a habilidade para configurar expressões regulares para forçar robustez de senha e formato. Deveria garantir usando hashing de senhas (que é o comportamento padrão), e não deveria armazenar credenciais na seção <CREDENCIAIS>da autenticação forms do arquivo de configuração de aplicação. 

Autorização 

Depois que uma identidade de usuário foi estabelecida para a solicitação, a identidade é armazenada no contexto do pedido, como um objeto System.Security.Principal.IPrincipal que está disponível via HttpContext.Current.User. Este objeto pode ser usado para tomar decisões de controle de acesso para o pedido. 

O ASP.NET provê dois mecanismos de autorização embutidos que controlam o acesso ao nível de URL: autorização de Arquivo e autorização de URL. Ambos executam depois da autenticação, na fase AuthorizeRequest do ASP.NET, e conferem se a identidade requisitante tem acesso à URL pedida. Se for determinado que a identidade não possa ter acesso, o pedido é terminado com uma resposta "401 Unauthorized" .

A autorização de arquivo só funciona quando a opção autenticação Windows for usada (quando o usuário principal contém uma identidade Windows), e usa a lista de controle de acesso do arquivo (ACLs) para determinar se a identidade requisitante deve ter permissão de acesso à URL. Note que a autorização de Arquivo também só funciona quando o pedido for mapeado para um arquivo e este está em uma máquina local. Se o arquivo físico estiver em um compartilhamento, esta autorização não tem nenhum efeito e permite o pedido. 

A autorização de arquivo pode ser usada por aplicações que autenticam usuários que têm contas Windows e que usam ACLs para controlar acesso aos recursos. Tenha certeza de remover o acesso de leitura para qualquer identidade de usuário que não deveria ter acesso a um determinado arquivo ao usar este tipo de autorização. 

A autorização de URL usa as regras de controle a acesso baseadas em configuração, que referenciam o nome do usuário ou seus papéis, como um modo para conceder ou negar acesso. Geralmente é o mecanismo de autorização preferido porque não depende da identidade usuário tenha uma conta Windows. Pode ser usado com qualquer mecanismo de autenticação que produz um usuário principal, e oferece um modo mais fácil de administrar políticas de acesso do que administrar ACLs em arquivos. 

Regras de autorização de controle de acesso por URL, podem ser especificadas em nível de URL, na seção de configuração <SYSTEM.WEB><AUTHORIZATION>. O mecanismo de autorização processará as regras numa ordem cima-para-baixo e selecionará a primeira regra que casar, adotando a ação de negar ou permitir especificada pela regra.
    
Alternativamente, também podemos qualificar as regras com nomes de usuário ou papéis. No ASP.NET 1.1, temos que associar uma lista de papéis manualmente a um usuário principal, depois da autenticação. No ASP.NET 2.0, podemos usar a classe System.Web.Security.RoleManager para criar e administrar papéis e estes papéis serão automaticamente associados a um usuário depois da autenticação. Também podemos usar tags locais para especificar regras de controle de acesso para URLs específicas no mesmo arquivo Web.config. 

A autorização de URL só deveria ser usada para permitir acesso ao conjunto específico de usuários e negar acesso a qualquer outro. Uma boa prática consiste em projetar uma configuração mais restritiva em nível do diretório raiz (negue todo mundo ou negue todo anônimo), com relaxamento específico para URLs individuais ou sub-pastas que têm menos restrições de acesso. Deveríamos considerar as exigências de autorização da aplicação ainda na fase de projeto, e tentar agrupar URLs com restrições de acesso semelhantes, em diretórios com um único conjunto de regras de autorização, para minimizar a necessidade de configurar muitas regras individuais, e assim reduzir o risco de obtê-las erroneamente. 

Autorização de Aplicação

A autorização em nível de URL é um bom modo de dar segurança à aplicação, e deveria ser usado onde quer que seja possível restringir acesso ao conjunto mínimo de usuários que precisam interagir com o sistema. Porém, às vezes a autorização em nível de aplicação é exigida para prover controle mais granular quanto à funcionalidade que está disponível para seus usuários. 

Tipicamente, a autorização de aplicação é executada inspecionando a autenticação do usuário principal atual, disponível na propriedade HttpContext.Current.User, e tomando uma decisão para conceder ou negar acesso à funcionalidade específica, baseado ou no nome de usuário ou no papel membership principal. Em aplicações ASP.NET, isto é tipicamente resolvido em duas fases: ocultando regiões de página e validando programaticamente  o acesso, antes de executar ações de servidor. 

Ocultar regiões de página é uma prática comum em aplicações existentes, e requer a exibição seletiva de um conjunto de controles de página via colocação destes controles em um painel que é configurado para ser visível ou invisível, baseado na identidade usuário ou no papel membership. No ASP.NET 2.0, esta tarefa é simplificada pelo controle LoginView, que provê um modo fácil de associar modelos aos usuários e papéis (veja http://beta.asp.net/QuickStartv20/aspnet/doc/security/login.aspx - Usando os Controles de Login -  para um exemplo de como usar este controle). Note, porém, que esta prática só não é o bastante. 

Além de ocultar partes de uma página, precisamos forçar que o controle de acesso nas ações atuais, seja feito pela aplicação em resposta às entradas do usuário. Estas ações geralmente são ASP.NET postbacks de páginas, que invocam os manipuladores de evento do servidor, ou codificam nos manipuladores de evento de página que agem em uma querystring, dados forms  ou outra entrada de cliente. No ASP.NET 1.1, ocultar um controle não impede que um cliente malicioso ative seus manipuladores de evento, portanto esta é uma prática obrigatória. No ASP.NET 2.0, os controles System.Web.UI.WebControls e namespaces de System.Web.UI.HtmlControl, impedem através de eventos de postback padrão, que sejam ativados se forem ocultos e controles personalizados também podem fazer o mesmo. 

Para forçar o controle de acesso, coloque o código em todo manipulador de evento ou método que executa uma ação crítica, para ter certeza de que o usuário atual está autorizado a executar a ação desejada. Deste modo, mesmo se o cliente conseguir invocar o manipulador de evento diretamente, só garantirá que seja autorizado aos usuários que podem executar a ação protegida. Podemos fazer isto, verificando o usuário principal diretamente ou usando comandos declarativos ou imperativos para o usuário principal. 

O código mostrado na Listagem 1 garante que o evento manipulador CreateDatabase, só permite que o nome de usuário Administrador ou todos os usuários no papel de Operador completem a chamada. Alternativamente, pode obrigar a autorização de código fazendo demandas para a classe System.Security.Permissions.PrincipalPermission. Esta classe pode ser usada para fazer demandas para um nome de usuário e um papel particulares, para o conjunto principal do usuário atual na thread. Pode também ser usado para fazer demandas programáticas e declarativas para o usuário principal. A Listagem 2 mostra dois exemplos de uso da PrincipalPermission, para exigir que o usuário seja o Administrador. 

Listagem 1 Controle de acesso para Manipuladores de Evento

void CreateDatabase_Click(Object source, EventArgs e) {

    System.Security.Principal.IPrincipal user = Context.User;
        if (user != null && user.Identity != null)
    {

        if (user.Identity.Name.Equals("Administrator") ||             user.IsInRole("Operator"))         {             CreateDatabase();             return;
        }      }


   throw new System.Security.SecurityException(         "You are not authorized to perform this action!"); }

Listagem 2 Autenticando com PrincipalPermission

[PrincipalPermission(SecurityAction.Demand,                      Name="Administrator",                      Role=null)] void CreateDatabase_Click(Object source, EventArgs e) {
    ... } void CreateDatabase_Click(Object source, EventArgs e) {     PrincipalPermission p = new PrincipalPermission(         "Administrator", null);
    p.Demand();     ...

}

O ASP.NET configurará o pedido principal atual na thread, depois que todos os manipuladores de evento dos módulos de autenticação e o AuthenticateRequest do global.asax executaram. Isto significa que se quisermos configurar no pedido um principal personalizado depois desta fase, temos que configurar a thread principal manualmente, atribuindo seu objeto principal à propriedade Thread.CurrentPrincipal. 

Acesso de Recursos

Além da autenticação e autorização baseada em usuário já vista, também é importante considerar como os recursos do Windows (arquivos, registro, objetos, SQL Servers remotos) são acessados dentro de uma aplicação ASP.NET. Dado que a abstração do usuário do ASP.NET é desacoplada das contas  do Windows, a identidade usada para acessar recursos Windows nem sempre é a identidade do usuário autenticado. Na realidade, a identidade acessada depende da identidade Windows personificada pela thread da aplicação, e pode ser quaisquer das identidades descritas na Tabela 3. 

Tabela 3 Identidades de Thread

Identidade

Descrição

Configuração

Process Identity

A identidade do processo em funcionamento que hospeda a aplicação ASP.NET. Tipicamente, este é um modo do Processo de Isolamento do Network Service do ISS 6.0 (IIS 6.0 Worker Process Isolation mode) O ASP.NET irá, por padrão, usar esta identidade para acessar recursos (exceto para UNC).

O pool de identidades de aplicação do IIS 6.0 no modo WP ou a conta especificada na seção de  configuração <SYSTEM.WEB><PROCESSMODEL>do ASP.NET. No tem configurações impessoais.

Authenticated User Identity

A identidade do usuário autenticado. É usada para acessar os recursos do Windows com a identidade cliente em aplicações Intranet, tal como para auditoria, usuários de Intranet, ou para gerenciar o acesso com contas Windows.

Foi usado um método de autenticação IIS diferente de anonymous. Se for usado anonymous, a identidade é, por padrão, a conta IUSR_MACHINE ou a conta anônima configurada. O ASP.NET é configurado para despersonalizar o cliente com <SYSTEM.WEB>.

UNC User Identity

A identidade do usuário autenticado ou usuário UNC configurado nos diretórios virtuais localizados num compartilhamento UNC.

Os mapeamentos de URL para um compartilhamento UNC e o IIS, está configurado para uma conta fixa de autenticação UNC.

Fixed Application Identity

A identidade especificada na configuração ASP.NET. É tipicamente usado para acessar recursos a uma conta especial com baixos privilégios ou para se conectar a recursos de rede com uma conta de domínio delegada.

O ASP.NET está configurado para despersonalizar uma identidade específica com <SYSTEM.WEB>.

Aplicações Intranet podem escolher personificar o cliente para limitar na aplicação os direitos de acesso do usuário. Porém, também aumenta a carga de administrar as permissões de recursos (arquivo ACLs e permissões do SQL Server, por exemplo) da aplicação, e introduz redução de desempenho devido, entre outras razões, ao pooling de conexão ineficiente ao banco de dados. Limitações adicionais existem para o acesso a recursos remotos, tal como acessar um SQL Server de banco de dados remoto com autenticação Integrada, porque a maioria dos esquemas de autenticação IIS, não produzem símbolos de autenticação que possam acessar máquinas remotas na rede (com exceção da autenticação Básica, ou se configuramos o Windows NT® Lan Manager ou a delegação do Kerberos). 

Uma opção, consiste em usar o projeto de subsistema seguro, onde a aplicação Web acessa recursos internos com uma única identidade, e garante que seus usuários têm a permissão para acessar estes recursos mediante autorização em nível de aplicação (previamente descrita). Esta é a abordagem padrão para o ASP.NET, com o modo de processamento de identidade despersonificado. Podemos também atingir o mesmo resultado com uma identidade de aplicação fixa, caso em que deveríamos proteger as credenciais por configuração encriptada. 

Ao usar a abordagem de subsistema seguro, lembre-se das seguintes melhores práticas:  

  • Execute cedo a autorização (como descrito antes neste artigo) e negue acesso a tudo com exceção dos usuários autorizados;
  • Rode aplicação com o menor privilégio possível. Se o atacante for persistente, pode fazer tanto dano quanto a identidade processo ou identidade aplicação permitir;
  • Só conceda o acesso mínimo necessário aos recursos. Com SQL Server, por exemplo, não conceda à aplicação identidade, direitos de Owner  do Banco de dados, só a concessão direitos as stored procedures necessários para sua funcionalidade, e retenha todos os demais direitos, incluindo SELECTS nas TABELAS.

Segurança de Ingresso de cliente

As aplicações Web ASP.NET geralmente usam a tag cliente para associar o estado de um usuário particular. Por exemplo, o mecanismo de autenticação Form ASP.NET previamente descrito, usa um cookie de cliente codificado, para permitir a um browser de cliente acessar a aplicação por um período de tempo, sem exigir as credenciais do usuário para todo pedido. Outros usuários de ingressos de cliente incluem o Role Manager, que usa um cookie para associar um conjunto de papéis de aplicação ao cliente, e Session State que usa um cookie para identificar o ID para a sessão do cliente. Todas estas características também podem usar ingressos baseados em URL no ASP.NET 2.0, como descreveremos adiante. O código da aplicação também pode armazenar estados personalizados no ViewState, em campos de forms e em cookies personalizados. 

Os ingressos, por serem expostos ao cliente, podem ser roubados, podem ser executados de novo, e podem ser alterados por clientes maliciosos, o que pode resultar em várias ameaças para a aplicação. Especificamente, estas ameaças incluem clientes maliciosos que roubam um ingresso de um usuário legítimo, e mascarados como aquele cliente, executam de novo aquele ingresso ou o examinam à procura de informação útil sobre a aplicação. Clientes maliciosos também poderiam modificar um ingresso personalizado, para fingir ser outro usuário ou explorar a aplicação de um modo específico. 

A seguinte, é uma orientação geral que se aplica a todos os ingressos de cliente usados por uma aplicação, a qual pode ajudar a mitigar ou reduzir o risco de todas estas ameaças. Se o ingresso contém informação segura da qual não quer que o cliente tome conhecimento, encripte o ingresso. Isto é suportado pela autenticação Forms, pelo Role Manager e pelas características de ViewState. Para a autenticação Form, configure o atributo de proteção <SYSTEM.WEB><AUTHENTICATION><FORMS>para All, o qual é o padrão. Para o role Manager, configure o atributo <SYSTEM.WEB><ROLEMANAGER>cookieProtection para All. 

Para o ViewState, configure o atributo EncriptaçãoMode para Always (sempre) na diretiva @ Page ou no elemento <SYSTEM.WEB><PAGES>. Porém, note que esta funcionalidade só está disponível no ASP.NET 2.0. No ASP.NET 1.1, a encriptação pode ser alcançada usando a ViewState de validação 3DES. 

A encriptação executada, depende das configurações dentro do elemento <MACHINEKEY>. Usando encriptação combatemos a segunda ameaça: usuários maliciosos que examinam o ingresso a procura de informação útil sobre a aplicação. A vantagem aqui, é claro, reside no desempenho, devido ao custo extra de runtime introduzido para decifrar o ingresso a cada pedido. 

Ao menos, deveríamos impedir que o ingresso seja modificado ou criado no cliente, habilitando as verificações de validação do Message Authentication Code (MAC). Esta verificação consiste em uma assinatura hash dos conteúdos de ingresso anexada ao mesmo, que permite ao servidor ter certeza de que ninguém interferiu com o ingresso através de re-computação do hash e o validou com a assinatura. 

Se ativar a encriptação para as características acima mencionadas, obterá os benefícios da validação MAC automaticamente. Além disto, o ViewState provê a habilidade para injetar um valor unívoco usado durante a validação, para ter certeza de que a view state blob foi gerado para o usuário atual, o que impede que outros usuários possam submeter um form no lugar de outro usuário. Isto é realizado programaticamente, configurando a propriedade ViewStateUserKey da página para um valor de usuário unívoco, tal como uma ID de sessão ou o nome de usuário autenticado, para todo pedido. 

Todas estas características permitem degradar a proteção de encriptação para proteção de só validação, o que não protege os dados de serem descobertos, mas os protegem de serem alterados pelo cliente. Isto combate a terceira ameaça: um usuário malicioso que consegue um ingresso personalizado para personificar outro usuário. 

Se tivermos dados personalizados que gostaríamos de armazenar de modo a impedir que sejam descobertos ou modificados pelo cliente, temos algumas opções. Podemos armazená-los na sessão, caso em que o estado é armazenado no servidor e o cliente só obtém a session ID. Também podemos armazenar os dados na região userData do ingresso encriptado da autenticação forms, no ViewState ou em um cookie personalizado com sua própria validação MAC e mecanismos de encriptação, embora isto exigirá que  administremos nossas próprias chaves. 

Com validação e encriptação habilitados, não combatemos ainda a ameaça de retomada de ingresso, a qual é o resultado de clientes maliciosos que podem roubar um ingresso válido e depois apresentá-lo ao servidor mascarando-se como o cliente original para o qual o ingresso foi emitido. Outra variação desta ameaça é um cliente malicioso que força o cliente legítimo a usar o ingresso provido pelo usuário malicioso. Há duas estratégias gerais que podem ajudar a reduzir este risco: impedindo que os ingressos sejam roubados, e impedindo que os ingressos sejam executados novamente. 

Para impedir que os ingressos sejam roubados, em primeiro lugar a aplicação deveria impedir que o ingresso fosse farejado no caminho de rede do cliente, e também garantir que o ingresso não foi roubado do cliente. O melhor método para proteger o caminho de rede é habilitar o SSL para todo o domínio Web, ou pelo menos para o escopo das URLs autenticadas e para a página de login. Se usar o último método, garanta que o caminho para a autenticação Form, para o Role Manager ou para ingresso personalizado baseados em cookies, seja atribuído ao segmento SSL protegido do namespace de URL. A atribuição do caminho é realizada tanto através da configuração do caminho, como através da atribuição do cookiePath para a autenticação Form e Role Manager, nas respectivas seções de configuração, ou programaticamente, configurando o atributo Path no objeto System.Web.HttpCookie que representa o cookie emitido por sua aplicação. Isto também pode interceptar cookies configurados através de outros componentes, examinando a coleção HttpResponse.Cookies, e forçar a atribuição do caminho nesses cookies, antes da resposta ser enviada ao cliente. Note que se estivermos usando ingressos baseados em URL, não há nenhum modo seguro para pedir ao cliente que restrinja estes ingressos a um namespace de URL particular. O mínimo que podemos fazer, é evitar a geração dos links para URLs não cobertas pelo SSL no conteúdo de aplicação. 

Lembre-se de que o SSL introduz uma penalidade de desempenho, assim, a decisão de cobertura dependerá das exigências da sua aplicação. Usando o SSL deste modo, garantimos que o ingresso não seja enviado em texto aberto em qualquer porção da aplicação que poderia receber o cookie de ingresso (que é emitido, por padrão, para todo o domínio) ou poderia ser ligado ao estado baseado em URL, ViewState ou armazenado em Form. Para aprender a habilitar o SSL no IIS, veja o Knowledge Base article Como habilitar o SSL para Todos os Clientes que interagem com seu Web Site em um Serviço de Informações Internet - http://support.microsoft.com/kb/298805

No ASP.NET 2.0,  as características  de autenticação Form e de Role Manager, também suportam as opções de configuração requireSSL e cookieRequireSSL, respectivamente, as quais permitem designar o uso de SSL para todas as URLs que podem gerar e podem aceitar ingressos para estas características. Se estiver usando o SSL, configure estas opções como true, para impedir a revelação acidental dos ingressos, quando são emitidos ou devolvidos em conexões de texto aberto. 

Infelizmente, mesmo se usarmos o SSL, os ingressos podem ser roubados no cliente. Isto pode acontecer em máquinas públicas, quando as janelas do browser são “left open” ou URLs que contêm ingressos baseados em URL são marcados. Também pode acontecer devido a ataques de scripting cross-site, que podem roubar cookies (adiante, mais sobre este assunto). 

A segurança em computadores públicos, deveria começar pelo encorajamento dos usuários no sentido de fechar as janelas do browser, quando terminaram de acessar o site, e fazendo com que o botão Log Out, fique altamente visível e prontamente disponível. Além disso, podemos considerar a implementação de um solução JavaScript personalizada, para detectar uma sessão de cliente inativa e fazer aparecer uma janela pop up que pergunta ao usuário se ainda está lá (e caso positivo, faz um pedido ao servidor para reinicializar a contagem de tempo da sessão). Esta prática funciona bem com intervalos de ingresso dos servidores mais curtos. Uma solução mais extrema está disponível no ingresso de autenticação Form, permitindo desabilitar a renovação do ingresso e forçar o cliente a fazer novamente o login depois de certo período de tempo, independentemente de haver atividade. Isto impede ao cliente malicioso conseguir capturar o ingresso e renová-lo para usá-lo indefinidamente, porque o ingresso sempre expirará após um lapso fixo de tempo. Isto é feito configurando como false, o atributo slidingExpiration no elemento <SYSTEM.WEB><AUTHENTICATION><FORMS>. 

No ASP.NET 2.0, características de cookie baseadas em ingresso emitirão automaticamente o cookie com o atributo HttpOnly, o que previne que alguns browsers; inclusive o Internet Explorer; tornem o cookie disponível para o JavaScript. Isto impede ataques de scripting cross-site destinados a roubar estes cookies de clientes que usam estes browsers. 

Outra melhor prática é evitar o uso de ingressos baseados em URL a menos que sejam absolutamente requeridos (por exemplo, se temos usuários móveis ou uma exigência de suporte a clientes que desabilitam cookies). Isto acontece porque ingressos baseados em URL, são mais suscetíveis a serem descobertos (marcados ou as URLs enviadas por e-mail) e serem usados em ataques tipo "phishing" (enviados através de e-mail ou colocados em um message board), para fazer com que outro usuário compartilhe o ingresso com um cliente malicioso. A melhor coisa a se fazer, é usar ingressos baseados em cookies para todas as características, mas se não pudermos fazê-lo, então usarmos uma das configurações de auto-deteção disponíveis no ASP.NET 2.0 para todas as características baseadas em ingresso, inclusive autenticação Form, Role Manager e session State. Os dois modos disponíveis são UseDeviceProfile (a abordagem recomendada), que usa as capacidades do browser do cliente para determinar se são suportados cookies e AutoDetect, que executa uma auto-deteção baseada em redirecionamento de suporte de cookie, antes de determinar o modo. Isto permite endereçar o ingresso baseado em URL para os clientes que o necessitam. 

Prevenindo Retomadas

Algumas estratégias estão disponíveis para impedir a retomada de ingressos. O estado de sessão do ASP.NET 2.0 provê um nível adicional de proteção para ingressos Baseados em URL, permitindo rejeitar e regenerar o ID de ingresso de sessão, quando uma sessão correspondente não é achada no servidor. Isto impede que clientes múltiplos compartilhem o mesmo ID de sessão, caso cliquem na mesma URL, o que pode ter sido provocado por um motor de busca ou pode ter sido postado por um cliente malicioso. Esta característica é habilitada por padrão, e pode ser designada para o atributo regenerateExpiredSessionId, do elemento de configuração <SESSIONSTATE>. 

Podemos também tentar validar se o cliente que provê o ingresso é o cliente original para quem o servidor emitiu o ingresso. Esta prática exige capturar atributos unívocos do cliente e codificá-los no ingresso (com encriptação e validação hash). Então, em cada pedido, podemos comparar os atributos do cliente com os atributos codificados no ingresso, rejeitando o ingresso não casados. Infelizmente, a melhor coisa a fazer com clientes HTTP padrão, é usar o cabeçalho do pedido do agente de usuário e o endereço de IP do cliente. Ambos são unívocos, especialmente o IP, caso o cliente for originário de um servidor proxy, usado por vários provedores de acesso inclusive AOL, mas pode prover algum nível extra de proteção.

Evitando Ataques Por Validação de Entrada

O melhor que poderíamos extrair deste artigo, deveria ser o velho princípio de segurança de que qualquer entrada é maligna! Isto é especialmente verdadeiro com aplicações Web, a maioria das quais recebem entrada de clientes anônimos remotos. Ao projetar sua aplicação, lembre-se de que não podemos esperar qualquer nível segurança do browser do cliente. Apenas imagine abrir uma sessão de telnet e digitar manualmente um pedido HTTP. O cliente pode enviar qualquer URL, cabeçalhos, cookies e campos de formulário, de forma completamente independente de como construimos as páginas e o JavaScript. 

Por causa disto, lembre-se de que quaisquer dados que a aplicação recebe dos Cookies, cabeçalhos, QueryStrings e coleções de campos Form, podem não ser seguros. Sempre deveríamos validar toda entrada antes de tomar qualquer decisão sensível baseada nela. Lembre-se de que mesmo se a aplicação não parece tomar qualquer decisão sensível quanto à segurança baseada na entrada, os componentes usados podem. Por outro lado, se está armazenando esta entrada em um meio de persistência confiável, tal como um arquivo ou banco de dados, ele poderá ser usado para comprometer outro sistema de software que consome dados. 

A validação de entrada é mais bem realizada, pela definição de qual é a entrada correta para a aplicação e rejeitando qualquer outra entrada que não se encaixa nesta definição. Podemos incluir validação de tipo, validação de comprimento de seqüência, validação de intervalo específica e validação de expressão regular de formato. Quanto mais rígida a validação, melhor. 

Para entradas que vem de controles de formulários ASP.NET, podemos usar os controles  associados ASP.NET Validator, para executar uma grande parte desta validação (só tenha certeza de sempre obrigar a validação do lado servidor, chamando Page.IsValid). Para todos os outros dados, execute a validação nos callbacks de página. Uma boa regra é executar a validação e rejeitar qualquer entrada inválida logo que possível, mas antes temos que validar o direito de entrada antes que seja usado. 

Alguns dados de entrada podem tomar muitas formas que tem o mesmo significado, como nomes de usuário Windows (user@domain.com ou domain\user) ou caminhos de arquivo e URLs. Ao lidar com tais dados, é crítico que sejam convertidos para um formato canônico antes de tomar qualquer decisão de autorização ou acesso a recursos baseada neles. Isto é conhecido como canonicalização, e freqüentemente é a fonte de muitas vulnerabilidades de segurança em software. Problemas acontecem quando duas camadas diferentes de software, tipicamente as camadas de autorização e acesso a recursos, fazem interpretações diferentes de uma seqüência não-canônica. 

Para ter certeza de que a aplicação não seja vítima deste problema, é melhor não aceitar tais dados do cliente, e administrá-los interiormente na aplicação. Se aceitarmos tal entrada, precisamos convertê-la para uma representação padrão, e termos certeza de que usamos um conjunto padrão de APIs para processá-las através das diferentes camadas da aplicação. Por exemplo, se estamos lidando com o arquivo de caminhos do sistema, usamos sempre a API System.IO.Path.GetFullPath para obter uma representação canônica do caminho, e outra API daquela classe para trabalhar com o caminho resultante (note que APIs de E/S nativas e APIs de E/S .NET usam um formato de canonicalização diferente, e converter seqüências de caminho .NET para código nativo podem conduzir a vulnerabilidades de canonicalização). Use a classe ASP.NET 2.0 System.Web.VirtualPathUtility para trabalhar com caminhos virtuais ASP.NET e evite fazer sua própria manipulação de dados de seqüência de caminho, porque é bem possível que possa perder um caso especial e isto acabe sendo prejudicial. 

As duas maiores ameaças de entrada mais comuns para uma aplicação Web, são o cross-site scripting e a SQL Injection. O Cross-site Scripting, também conhecido como XSS, tenta forçar um browser a rodar código do lado cliente, submetendo um fragmento de script codificado como entrada para uma aplicação Web que a ecoa via resposta, não necessariamente para o mesmo cliente. O XSS pode ser usado para roubar cookies de autenticação, ou modificar o conteúdo exibido pelo browser com intenção maliciosa. Ataques de XSS são mitigados, rejeitando qualquer entrada que possa conter scripts XSS como parte da estratégia de validação de entrada, e codificando em HTML a entrada que é ecoada para o cliente tornando os scripts XSS completamente inofensivos. 

O ASP.NET 1.1 provê a opção validateRequest que descobre assinaturas XSS comuns em entradas para páginas ASP.NET e encerra o pedido. Se puder, mantenha esta opção habilitada nas páginas, mas lembre-se de que isto não se aplica para conteúdo que não é de página, e esta opção por si só, não é suficiente para prover validação de entrada para a aplicação. 

Se escrever a resposta manualmente ou desenvolver um controle personalizado, sempre codifique em HTML a saída da aplicação que irá conter entrada de cliente, usando o HttpUtility.HtmlEncode e métodos de HttpUtility.UrlEncode. Os controles ASP.NET 2.0 GridView e DetailsView, provêem a habilidade para codificar em HTML, partes da saída  que está ligada a dados. Porém, em todos os outros casos é responsável por codificar em HTML, as seqüências consideradas não confiáveis antes de atribuir propriedades que afetem o controle de saída. 

Como uma medida de defesa em profundidade, algumas características do ASP.NET 2.0 configuram o atributo HttpOnly nos cookies, para impedir que sejam acessados através de script do lado cliente. Também deveríamos configurar esta propriedade nos cookies personalizados . 

O SQL Injection recorre a outra forma de injeção de script, só que desta vez, injetando pedaços especialmente extraídos de parâmetros de entrada de consultas SQL, que são usados para a aplicação construir consultas SQL dinâmicas. Este pode ser um ataque muito perigoso, pois pode permitir ao atacante roubar dados sensíveis do banco de dados e em alguns casos também alterá-los. 

Para impedir ataques SQL Injection, além de usar validação de entrada forte, não devemos construir consultas com SQL dinâmico, baseadas em entradas do cliente. Em lugar disto, usamos consultas fixas ou stored procedures com parâmetros fortemente tipados, que são inicializados com a entrada do cliente.

ASP.NET e CAS 

O ASP.NET provê um modelo de segurança de acesso a código (CAS – code access security) que trabalha com o mecanismo  de segurança de código de acesso no .NET Framework. O ASP.NET usa principalmente seu modelo CAS para “encaixotar” o código da aplicação Web, tanto como um mecanismo de menor privilégio e também para isolar múltiplas aplicações ASP.NET em um servidor compartilhado. 

O CAS ASP.NET está baseado em níveis de confiança (veja Tabela 4) e pode ser configurado para cada aplicação designando o atributo trustLevel dentro da seção de configuração <SYSTEM.WEB><FORMS>. Os níveis de confiança disponíveis estão definidos dentro da seção de configuração <SYSTEM.WEB><SECURITYPOLICY>, e mapeiam cada nível de entrada confiável para um arquivo de política de segurança que contém as permissões correspondentes permitidas para a aplicação naquele nível (os arquivos ficam situados dentro do diretório version\CONFIG do .NET Framework). Ambas as seções deveriam ser bloqueadas na configuração ao nível de máquina, quando a aplicação não for confiável, para impedir que possa anular a configuração de nível de confiança do arquivo Web.config.

Tabela 4 Níveis de Confiança CAS Padrão

Nível de Confiança

Descrição

Full

A aplicação tem acesso irrestrito para todas as APIs, inclusive chamadas a código nativo (padrão).

High

A aplicação não pode chamar código nativo, mas pode fazer quase tudo o mais.

Medium

A aplicação está “encaixotada” para impedir que acesse recursos fora do seu controle, tais como acesso a arquivos fora da raiz da aplicação ou abrir conexões de rede.

Low

A aplicação pode usar a maior parte das características do ASP.NET, mas tem restrições de acesso a recursos for a do seu controle. Este é o nível de confiança mais adequado para aplicações não confiáveis num servidor hospedeiro.

Minimal

A aplicação tem um nível de confiança altamente restrito. Neste nível, as aplicações usarão características ASP.NET embutidas e muito pouco ou nenhum código.

Em tempo de execução, o conjunto de permissões no arquivo de política de confiança é associado a todo o código do usuário, incluindo assemblys compilados no diretório /Bin, páginas personalizadas e código em controles, e código localizado no diretório App_Code. Para ser exato, o conjunto resultante de permissões é uma interseção das permissões ao nível de aplicação especificadas no arquivo de políticas de confiança ASP.NET, com as permissões ao nível de empresa, máquina e usuário da configuração de hierarquia do CAS, onde cada nível inferior, só reduz o conjunto de permissões concedida pelos nível superior. 

Usando níveis de confiança com conjuntos de permissões mais restritivos, podemos diminuir o potencial de dano da aplicação caso a mesma esteja comprometida, e “encaixotar” a aplicação restringindo as operações, para aquelas que não podem afetar outras aplicações no computador. É recomendado testar e rodar as aplicações no nível de confiança médio (médium) se são confiáveis, e nível de confiança baixo se não são confiáveis (especialmente em um servidor compartilhado). Note que rodar em nível de confiança parcial introduz uma penalidade de desempenho, portanto isto pode não ser apropriado em alguns cenários. Por padrão, o ASP.NET usa o nível de confiança pleno (full), que permite que a aplicação só tenha acesso irrestrito na máquina específica, sujeito às limitações de segurança do Windows. 

Sua aplicação pode encontrar vários problemas comuns devido a permissões insuficientes, ao rodar com confiança parcial. Vários assemblys do sistema exigem que o visitante seja completamente confiável, pela omissão do atributo Permitir Assemblys de Visitantes Parcialmente Confiáveis - APTCA, o que efetivamente os torna não utilizáveis com confiança parcial. Nesta situação, existe a opção de impedir o uso destes assemblys da aplicação ou encapsular a funcionalidade necessária em um assembly encapsulante registrado no Global Assembly Cache - GAC e que tenha o atributo APTCA configurado e a assertiva de permissão irrestrita no envelopador. Caso escolhermos este último, devemos ser extremamente cuidadosos ao validar e restringir o uso do assembly encapsulante para o nível mínimo exigido, e exigir um outro conjunto de permissões para reduzir a área de contato do novo assembly. 

Outros códigos usados pela aplicação, podem exigir permissões em tempo de execução que não são concedidos pelo arquivo de política ativo. Nesta situação, existe ainda a opção anterior, mas também podemos acrescentar o nível mínimo da permissão necessária ao arquivo de política desejado. Isto será provavelmente necessário para qualquer código que exige permissões personalizadas, para as quais os arquivos de confiança parcial do ASP.NET não tem conhecimento.

Os níveis de confiança do ASP.NET, não se aplicam ao código ASP.NET interno, o qual sempre executa com permissões irrestritas. Isto significa que a aplicação pode ser potencialmente configurada para executar ações que são proibidas para código personalizado, principalmente por atribuições de configuração ou atribuições declarativas em páginas e controles ASP.NET. Por exemplo, embora não possamos nos conectar ao Servidor SQL via nosso próprio código, podemos configurar o controle SqlDataSource para conectar e executar consultas, porque faz parte do assembly System.Web e é registrado no GAC. O ASP.NET 2.0 minimiza este problema provendo uma opção para executar o caminho  do código de processamento completo de confiança da aplicação, inclusive o caminho interno do código de processamento da página e o processamento do controle ASP.NET associado. Isto é configurado com o atributo processRequestInApplicationTrust da seção de configuração <SYSTEM.WEB><FORMS>, e é habilitado por padrão. Esta atribuição pode fazer com que algum código pare quando for registrado no GAC, devido à suposição de que executará com permissões irrestritas. 

Para lidar com esta situação, e também para simplificar a administração da segurança de permissões, várias características do ASP.NET confirmam todas as permissões requeridas para execução e obrigam a aplicação a rodar em um nível de confiança particular, como determinado pela AspNetHostingPermission, concedida em cada um dos arquivos de política de nível de confiança. Por exemplo, a característica de estado de sessão pode ser usada em todos os níveis de confiança, mas os modos de estado de memória SQL e State Server externos ao processo, requerem confiança média e confirmam todas as outras permissões (como SqlClientPermission e SocketPermission, respectivamente). 

Note que o CAS é completamente independente do modelo de segurança Windows. O CAS usa permissões concedidas a um trecho de código e o Windows usa privilégios e objetos ACL expressos em termos da identidade Windows de processo ou thread. O CAS restringe também o conjunto de ações que o código gerenciado em um processo Windows pode executar, mas não substitui a segurança do Windows e nem permite que o código gerenciado passe por cima da mesma. O CAS só pode controlar o acesso a código gerenciado das API. Se uma aplicação pode chamar código nativo, então poderá passar por cima de todas as restrições do mesmo. Por isso, nunca deveríamos usar uma identidade Windows com baixos privilégios para os processos operários.

Auditando com Web Events

Auditagem é o processo de monitorar o uso de aplicações e coletar informação relevante sobre segurança. É uma parte importante da operação das aplicações, pois permite detectar e parar brechas potenciais de segurança, assim como investigá-las após o fato consumado, para futura prevenção. Em certos casos, a auditagem pode ajudar a identificar o atacante e adotar ações contra o mesmo.

No ASP.NET, a infra-estrutura de auditagem da aplicações é implementada através da característica de eventos Web. Eventos Web são um framework para a emissão de informação valiosa para um ou mais provedores configuráveis, incluindo a contribuição de controles de valiosos, que definem como e para onde os eventos serão enviados. O ASP.NET fornece uma hierarquia básica de classes de eventos, que são usadas pelo próprio framework para prover informação útil sobre a execução de uma aplicação, e podem também ser usados como uma fundação para eventos personalizados provocados pelo código da sua aplicação. Um caso de tais eventos que é interessante por uma perspectiva de segurança, são os eventos de auditoria de segurança, que derivam da classe System.Web.Management.WebAuditEvent como mostrado na Tabela 5. 

Tabela 5 Eventos de Auditoria de Segurança no ASP.NET 2.0

Evento

Descrição

WebAuditEvent

Classe básica para todos os eventos de auditoria.

WebFailureAuditEvent

Classe básica para todos os eventos de falha de auditoria, que são provocados sempre que uma ação de segurança falha. O ASP.NET provoca estes eventos quando a autorização de URL ou de arquivo falha na autorização do pedido.

WebSuccessAuditEvent

Classe básica para todos os eventos de auditoria bem sucedidos, que são provocados sempre que uma ação de segurança é bem sucedida. O ASP.NET provoca estes eventos quando a autorização de URL tem sucesso ao autorizar um pedido.

WebAuthenticationFailureAuditEvent

Classe básica para todos os eventos de falha de auditoria, que são provocados sempre que uma tentativa de autenticação falha. O ASP.NET provoca estes eventos quando provedores Membership ou a autenticação de formulário falham na validação das credenciais fornecidas ou quando a autenticação do ingresso de formulário falha na decriptação  ou na validação.

WebAuthenticationSuccessAuditEvent

Classe básica para todos os eventos de auditoria bem sucedidos, que são provocados sempre que uma tentativa de autenticação é bem sucedida. O ASP.NET provoca estes eventos quando provedores Membership ou a autenticação de formulário tem sucesso na validação das credenciais fornecidas.

WebViewStateFailureAuditEvent

A classe para o evento de falha de auditoria de ViewState, que é provocada sempre que o ASP.NET falha no processamento do ViewState, devido a um problema de encriptação ou validação.

Se estivermos executando autorização de aplicação personalizada, acessando recursos críticos ou executando qualquer outra operação relativa à segurança, deveríamos considerar instrumentá-lo, criando e provocando um evento personalizado derivado ou da classe WebAuditEvent ou da combinação das classes  WebAuditFailureEvent e WebAuditSuccessEvent. 

A Listagem 3 mostra um evento personalizado que é provocado quando um página .aspx não conseguiu validar um parâmetro de entrada. Podemos capturar os eventos de auditoria desejados configurando uma regra de eventos Web, para direcionar todos os eventos que derivam de uma classe básica de auditoria particular, para um provedor específico, e configurar o evento de supressão apropriado e as atribuições de buffer baseadas nas exigências. O evento de supressão permite restringir a taxa de eventos gerada pela aplicação, cancelando eventos sempre que a taxa exceder esta configuração, e o buffer permite acomodar picos de eventos, através do buffer de eventos em memória e eliminando-os de uma maneira inteligente, para proteger o canal de entrega de eventos. É altamente recomendado o uso de um provedor que suporte buffer, como o System.Web.Management.SqlWebEventProvider, de forma a poder usar atribuições de supressão mais relaxadas para evitar a perda de eventos, mas ainda podendo acomodar um grande fluxo destes. 

Listagem 3 Eventos de Validação de Entrada Personalizados



Note que as operações normais da aplicação, irão gerar abundantes sucessos de auditoria, que podem não ser muito interessantes de uma perspectiva de segurança e podem provocar um aumento da taxa de eventos alta, que acabará impactando o desempenho da aplicação ou contribuirá para uma condição de negação de serviço. Eventos Web esperam que a supressão de atribuições conduza a perda de eventos sob condições da altas taxa destes. O número seqüencial em cada evento, indicará quantos foram provocados de fato, quando nem todos os eventos são capturados pelo provedor. 

Figure 11 Auditing Event Raised by Invalid Membership Credentials  

Figura 3 Evento de Auditoria Provocado por Credenciais Membership Inválidas

Por padrão, são capturados apenas eventos de falha de auditoria no provedor de eventos de log, e aparecerá no máximo um por minuto para impedir o transbordamento do event log. A Figura 3 mostra um WebAuthenticationFailureAuditEvent provocado pelo provedor Membership, quando a aplicação tentou autenticar um usuário com credenciais inválidas.

Resumindo

O IIS 6.0 e o ASP.NET fornecem uma sólida plataforma Web para aplicações criadas tendo a segurança em mente. Mas no final das contas, é responsabilidade da aplicação adotar as melhores práticas de segurança, para evitar a introdução de vulnerabilidades potenciais. Isto significa que temos que prestar atenção a estas melhores práticas durante o projeto, desenvolvimento e distribuição das aplicações, e termos certeza de que a aplicação tem uma estrutura forte por se proteger. As práticas mencionadas neste artigo, devem ajudá-lo a avaliar os aspectos críticos de segurança da aplicação, e dar algumas idéias a respeito de como tirar vantagem das características de segurança da plataforma, disponíveis no IIS e no ASP.NET. 

Pelo fato de que constantemente são descobertos novos tipos de ataques e novos modos de explorar software, seguir os princípios de menor privilégio, área de contato reduzida e defesa em profundidade ao longo do ciclo de vida da aplicação, pode ajudar a minimizar futuros ataques imprevistos. Práticas de projeto mais seguras estão disponíveis em "Introdução à Aplicação de Segurança na Web" (Introduction to Web Application Security - http://msdn.microsoft.com/library/en-us/secmod/html/secmod71.asp), nos padrões e guia de práticas, uma fonte muito boa como guia de segurança de aplicação Web, que pode ser usada para aprender mais sobre idéias específicas aqui examinadas. Uma fonte para mais práticas de segurança no ASP.NET 2.0, pode ser achada em Práticas de Segurança: Praticas de Segurança com o ASP.NET 2.0 num Relance (Security Practices: ASP.NET 2.0 Security Practices at a Glance - http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGPractices0001.asp).

Michael Volodarsky é Gerente Técnico de Programa para a Web Platform e Tools Team na Microsoft. Possui a infra-estrutura fundamental de servidor para o ASP.NET e o IIS e está dedicado agora ao melhoramento da Web application platform para a próxima geração do Web Server, IIS 7.0.