Informativos sobre segurança

A segurança da configuração dos aplicativos Web revisitada

Bryan Sullivan

Bryan SullivanHá alguns anos — antes de fazer parte da Microsoft e da equipe do SDL (Ciclo de vida do desenvolvimento da segurança) — eu escrevi um artigo sobre os perigos das configurações inseguras do web.config e mencionei os dez piores vilões. Esse artigo ainda pode ser encontrado — basta procurar por “Top 10 Application Security Vulnerabilities in Web.Config Files” no seu mecanismo de pesquisa favorito. As vulnerabilidades de configuração abordadas na época ainda são relevantes e sérias atualmente, embora elas provavelmente não fossem grandes surpresas para os leitores regulares da MSDN Magazine. Ainda é importante habilitar erros personalizados, ainda é importante desabilitar o rastreamento e a depuração antes que o seu aplicativo seja enviado por push para produção, e ainda é importante exigir SSL para cookies de autenticação.

Na coluna deste mês, eu gostaria de continuar a partir do ponto em que parei naquele artigo, e discutir algumas das configurações de segurança incorretas mais obscuras, porém igualmente sérias. Também vou abordar uma nova ferramenta gratuita da equipe de ferramentas de segurança da informação da Microsoft, chamada Web Application Configuration Analyzer, que pode ajudar a localizar esses problemas. Lembre-se de que, até mesmo o aplicativo ASP.NET codificado da forma mais segura pode ser invadido se não estiver configurado corretamente.

EnableEventValidation

Um dos erros mais comuns que vejo os desenvolvedores cometerem é fornecer aos usuários uma lista de opções e pressupor que eles de fato escolherão um daqueles valores. Parece lógico: se você adicionar um controle ListBox a uma página e populá-la previamente com a lista de todos os estados dos Estados Unidos, deverá obter “Washington” ou “Georgia” ou “Texas”; e não “Foo” ou “!@#$%” ou “<script>alert(document.cookie);</script>”. Talvez não haja um meio de especificar valores assim usando o aplicativo da maneira tradicional, com um navegador, mas existem muitas formas de acessar aplicativos Web sem usar qualquer navegador! Com uma ferramenta de proxy da Web como o Fiddler de Eric Lawrence (que continua sendo uma das minhas ferramentas favoritas para localizar vulnerabilidades de segurança em aplicativos Web, e que pode ser baixada em fiddler2.com), você pode enviar qualquer valor desejado para qualquer campo do formulário. Se o seu aplicativo não estiver preparado para essa possibilidade, ele poderá falhar de maneiras potencialmente perigosas.

A configuração de EnableEventValidation é um mecanismo de proteção abrangente para ajudar na defesa contra ataques dessa natureza. Se um usuário mal-intencionado tentar enviar um valor inesperado para um controle que aceita uma lista de valores finita (como uma ListBox — mas não como uma TextBox, que já pode aceitar qualquer valor), o aplicativo detectará a adulteração e acionará uma exceção.

Ruim:

<configuration>

  <system.web>

    <pages enableEventValidation="false"/>

Bom:

<configuration>

  <system.web>

    <pages enableEventValidation="true"/>

PasswordFormat

A estrutura do provedor de associação fornecida como parte do ASP.NET (a partir do ASP.NET 2.0) é um excelente recurso que evita que os desenvolvedores tenham que reinventar a roda da funcionalidade de associação todas as vezes. Em geral, os provedores internos são muito bons do ponto de vista de segurança quando deixados em suas configurações padrão. No entanto, se as configurações de associação forem alteradas, elas poderão se tornar significativamente menos seguras.

Um bom exemplo disso é a configuração de PasswordFormat, que determina como as senhas dos usuários são armazenadas. Você tem três opções: Clear, que armazena as senhas em texto sem formatação; Encrypted, que criptografa as senhas antes de armazená-las; e Hashed, que armazena hashes das senhas em vez das próprias senhas. Dentre essas opções, Clear é certamente a pior. Nunca é adequado armazenar senhas em texto sem formatação. Encrypted é uma opção melhor e a melhor alternativa é Hashed, pois a melhor maneira de armazenar um segredo é não armazená-lo de forma alguma. No entanto, como não existe nenhuma maneira de recuperar a senha original de um hash, se um usuário esquecer a sua senha, você não será capaz de recuperá-la para ele.

Ruim:

<configuration>

  <system.web>

    <membership>

      <providers>

        <clear/>

        <add name="AspNetSqlMembershipProvider" 

             passwordFormat="Clear"

             ...

 />

Melhor:

<configuration>

  <system.web>

    <membership>

      <providers>

        <clear/>

        <add name="AspNetSqlMembershipProvider" 

             passwordFormat="Encrypted"

             ...

 />

Excelente:

<configuration>

  <system.web>

    <membership>

      <providers>

        <clear/>

        <add name="AspNetSqlMembershipProvider" 

             passwordFormat="Hashed"

             ...

 />

MinRequiredPasswordLength e MinRequiredNonalphanumericCharacters

Dois valores das configurações de associação devem ter seus padrões alterados: as propriedades MinRequiredPasswordLength e MinRequiredNonalphanumericCharacters. Para objetos AspNetSqlMembershipProvider, essas configurações têm como padrão um requisito de tamanho mínimo de senha de seis caracteres, sem qualquer exigência de caracteres não alfanuméricos. Para melhor segurança, essas configurações devem ser definidas com valores bem mais altos. Você deve exigir pelo menos uma senha de 10 caracteres, com dois ou mais caracteres não alfanuméricos. Um mínimo de 14 caracteres com quatro ou mais caracteres não alfanuméricos seria ainda melhor.

É verdade que o tamanho e a complexidade da senha são facas de dois gumes: quando você exige que os usuários definam senhas mais longas e mais complexas, há uma probabilidade menor de essas senhas serem descobertas com ataques de força bruta, porém, existe também uma possibilidade proporcionalmente maior de os usuários não conseguirem se lembrar de suas senhas e serem forçados a anotá-las. No entanto, embora isso pareça uma terrível falha de segurança potencial, muitos especialistas em segurança acreditam que os benefícios superem os riscos. O conhecido guru da segurança Bruce Schneier, para começar, sugere que os usuários criem senhas longas e complexas, e que elas sejam armazenadas na bolsa ou na carteira, que são lugares onde as pessoas costumam guardar pequenos pedaços de papel.

Ruim:

<configuration>

  <system.web>

    <membership>

      <providers>

        <clear/>

        <add name="AspNetSqlMembershipProvider" 

             minRequiredPasswordLength="6"

             minRequiredNonalphanumericCharacters="0"

             ...

 />

Bom:

<configuration>

  <system.web>

    <membership>

      <providers>

        <clear/>

        <add name="AspNetSqlMembershipProvider" 

             minRequiredPasswordLength="14"

             minRequiredNonalphanumericCharacters="4"

             ...

 />

O site de segurança online da Microsoft (microsoft.com/protect/fraud/passwords/create.aspx) também sugere que os usuários devem anotar suas senhas, e contém informações adicionais sobre como criar e proteger senhas fortes.

ValidateRequest

O XSS (scripts entre sites) continua sendo a vulnerabilidade mais comum da Web. Um relatório publicado pela Cenzic Inc. em julho descobriu que, na primeira metade do ano, as vulnerabilidades de XSS responderam por 28% de todos os ataques na Web. Devido às consequências potencialmente graves de uma vulnerabilidade de XSS — com frequência eu chamei o XSS de “estouro de buffer da Web” no passado — a lógica é que os desenvolvedores devem fazer o que puderem para ajudar a defender seus aplicativos contra esse ataque. É muito bom quando você obtém uma defesa que basicamente não custa nada, e a propriedade ValidateRequest é exatamente isso.

Ruim:

<configuration>

  <system.web>

    <pages validateRequest="false" />

Bom:

<configuration>

  <system.web>

    <pages validateRequest="true" />

A propriedade ValidateRequest funciona testando a entrada do usuário quanto à presença de padrões de ataque comuns; por exemplo, verificando se a cadeia de entrada contém colchetes angulares (<). Se tiver, o aplicativo acionará uma exceção e interromperá o processamento da solicitação. Embora essa não seja uma solução completa por si só — você também deve sempre aplicar a lógica de codificação de saída e validação/limpeza de entrada, como existe internamente na Microsoft Web Protection Library — a propriedade ValidateRequest não bloqueia muitos tipos de ataques de XSS populares. É melhor deixar a propriedade ValidateRequest habilitada sempre que possível.

MaxRequestLength

Nem sempre é uma boa ideia permitir que os usuários façam solicitações HTTP grandes arbitrariamente ao seu aplicativo. Isso deixa você vulnerável a ataques de DoS (negação de serviço), em que um único invasor pode usar toda a sua largura de banda, seus ciclos de processador ou seu espaço em disco e deixar o seu aplicativo indisponível para qualquer um dos outros usuários legítimos que você está tentando alcançar.

Para ajudar a evitar isso, você pode definir a configuração da propriedade MaxRequestLength com um valor adequadamente baixo. O valor padrão é 4096 KB (4 MB). Uma vez que os diferentes aplicativos possuem diferentes requisitos de tamanho de solicitações usuais e excepcionais, é difícil criar uma boa regra prática sobre a definição do valor de MaxRequestLength. Portanto, em vez de dar exemplos do que é “ruim” e “bom” em termos de configuração, eu apenas sugiro que você tenha em mente o fato de que, quanto maior for o valor definido, maior será o risco de um ataque de DoS:

<configuration>

  <system.web>

    <httpRuntime maxRequestLength="4096"/>

EnableViewStateMac

Eu escrevi anteriormente sobre a configuração de EnableViewStateMac na coluna de Informativos sobre segurança de julho de 2010, sobre a segurança do estado de exibição (msdn.microsoft.com/magazine/ff797918). Para aqueles que não leram, EnableViewStateMac é uma defesa para evitar que os invasores adulterem o estado de exibição do lado do cliente. Quando a propriedade EnableViewStateMac está habilitada, o aplicativo ASP.NET adiciona um MAC (Message Authentication Code) de criptografia ao valor do formulário __VIEWSTATE oculto. Não há nenhuma maneira de um invasor determinar um MAC válido para um ataque arbitrário — na tentativa de inviabilizar o estado de exibição de uma vítima para injetar algum JavaScript malicioso, por exemplo —, então, se um invasor tentar adulterar o estado de exibição dessa maneira, o MAC será inválido e o aplicativo ASP.NET bloqueará a solicitação.

Ruim:

<configuration>

  <system.web>

    <pages enableViewStateMac="false"/>

Bom:

<configuration>

  <system.web>

    <pages enableViewStateMac="true"/>

Se você estiver implantando o aplicativo em um ambiente de farm de servidores, não se esqueça de especificar manualmente uma chave para o MAC, em vez de deixar que o aplicativo gere chaves aleatórias automaticamente. (Se você não especificar as chaves manualmente, cada computador do farm irá gerar automaticamente uma chave diferente, e o MAC do estado de exibição criado por qualquer um dos computadores será considerado inválido e será bloqueado por qualquer um dos outros computadores.)

Existem algumas diretrizes adicionais que você deve seguir ao criar manualmente as chaves, para garantir o máximo de segurança para o seu estado de exibição. Em primeiro lugar, especifique um dos algoritmos de criptografia aprovados pelo SDL. Para aplicativos que utilizam o Microsoft .NET Framework 3.5 ou anterior, isso significa usar o SHA1 (que é o algoritmo padrão) ou o AES. Para aplicativos que utilizam o .NET Framework 4, você também pode usar o HMACSHA256, o HMACSHA384 ou o HMACSHA512. Evite algoritmos fracos como o MD5.

Ruim:

<configuration>

  <system.web>

    <machineKey validation="MD5" validationKey="..."/>

Bom:

<configuration>

  <system.web>

    <machineKey validation="AES" validationKey="..."/>

Escolher uma chave forte é tão importante quanto escolher um algoritmo forte. Use um gerador de números aleatórios criptograficamente fortes para gerar uma chave de 64 bytes (128 bytes se você estiver usando o HMACSHA384 ou o HMACSHA512 como algoritmo de chave). O código de exemplo de referência para gerar chaves adequadas é fornecido na coluna Informativos sobre segurança de julho de 2010, mencionada anteriormente.

Ruim:

<configuration>

  <system.web>

    <machineKey validation="AES" validationKey="12345"/>

Bom:

<configuration>

  <system.web>

    <machineKey validation="AES" validationKey="143a907bb73069a2fe7c..."/>

ViewStateEncryptionMode

Assim como você deve aplicar um MAC ao estado de exibição do seu aplicativo para evitar que invasores potenciais o adulterem, você também deve criptografar o estado de exibição para evitar que eles o leiam. A menos que você esteja totalmente certo de que não existem informações confidenciais em nenhum dos estados de exibição, é mais seguro definir a propriedade ViewStateEncryptionMode para criptografá-los e protegê-los.

Ruim:

<configuration>

  <system.web>

    <pages viewStateEncryptionMode="Never"/>

Bom:

<configuration>

  <system.web>

    <pages viewStateEncryptionMode="Auto"/>

Novamente, assim como acontece com a propriedade EnableViewStateMac, você tem várias opções de algoritmos de criptografia que o aplicativo usará para criptografar o estado de exibição. No entanto, é melhor ficar com o AES, que é o único algoritmo disponível atualmente aprovado pelos Padrões de criptografia do SDL.

Ruim:

<configuration>

  <system.web>

    <machineKey decryption="DES" decryptionKey=""/>

Bom:

<configuration>

  <system.web>

    <machineKey decryption="AES" decryptionKey=""/>

Finalmente, lembre-se de que, se você estiver implantando o aplicativo em um farm de servidores, precisará especificar uma chave manualmente. Defina para a chave um valor criptograficamente aleatório de 24 bytes.

Ruim:

<configuration>

  <system.web>

    <machineKey decryption="AES" decryptionKey="12345"/>

Bom:

<configuration>

  <system.web>

    <machineKey decryption="AES" decryptionKey="143a907bb73069a2fe7c..."/>

UseUnsafeHeaderParsing

Quando os desenvolvedores são suficientemente frustrados por um bug difícil, é frequente implementarem qualquer alteração sobre a qual tenham lido e que corrija o problema, sem realmente entender o que estão fazendo com seu aplicativo. A configuração de UseUnsafeHeaderParsing é um ótimo exemplo desse fenômeno. Embora a palavra “unsafe” (inseguro) no nome da propriedade já seja suficiente para levantar uma bandeira vermelha para a maioria das pessoas, uma pesquisa rápida na Internet revela praticamente milhares de resultados sugerindo que os desenvolvedores habilitem essa propriedade. Se você habilitar a propriedade UseUnsafeHeaderParsing, o seu aplicativo irá ignorar muitas das especificações HTTP RFC e tentará analisar as solicitações malformadas. Embora esse procedimento possa permitir que o seu aplicativo funcione com clientes de HTTP que não seguem os padrões do HTTP (motivo pelo qual muitas pessoas o sugerem como uma correção do problema), ele também pode deixar seu aplicativo vulnerável a ataques de cabeçalho malformado. Evite riscos e deixe essa configuração desabilitada.

Ruim:

<configuration>

  <system.net>

    <settings>

      <httpWebRequest 

       useUnsafeHeaderParsing=

       "true"/>

Bom:

<configuration>

  <system.net>

    <settings>

      <httpWebRequest 

       useUnsafeHeaderParsing=

       "false"/>

Web Application Configuration Analyzer (WACA)

Agora que já vimos algumas configurações perigosas, vamos dar uma olhada em uma ferramenta que pode ajudar a automatizar a localização dessas configurações no seu código. Afinal de contas, embora a análise manual do código possa ser útil, a análise automatizada pode ser mais meticulosa e consistente. Você também vai se livrar do trabalho enfadonho de analisar manualmente os arquivos XML e terá mais tempo para resolver problemas mais interessantes!

A equipe de ferramentas de segurança da informação da Microsoft lançou algumas ferramentas de segurança excelentes, incluindo duas — AntiXSS/Web Protection Library e CAT.NET — que tornamos obrigatórias para todos os produtos e serviços internos do .NET Framework da Microsoft, como parte do Microsoft SDL. Sua versão mais recente, WACA, foi desenvolvida para detectar configurações incorretas potencialmente perigosas, como aquelas que mencionei neste artigo e no meu artigo anterior sobre as 10 vulnerabilidades mais comuns do web.config. Alguns exemplos de verificações do WACA:

  • O rastreamento está habilitado?
  • O MaxRequestLength é muito grande?
  • Os cookies HttpOnly estão desabilitados?
  • O SSL é necessário para logon de autenticação de formulários?
  • O atributo EnableViewStateMac está definido como false?

Além disso, o WACA também pode verificar se existem configurações incorretas no próprio IIS e no banco de dados SQL, e até mesmo se há problemas no nível de sistema. Alguns exemplos incluem:

  • O serviço Firewall do Windows está desabilitado?
  • O administrador local chama-se “Administrador”?
  • O arquivo de log do IIS está na unidade do sistema?
  • O execute está habilitado no diretório virtual do aplicativo?
  • Os bancos de dados de exemplo estão presentes no SQL Server?
  • O xp_cmdshell está habilitado no SQL Server?

Enquanto os desenvolvedores e testadores provavelmente usarão o WACA principalmente para verificar as configurações de seus aplicativos, os administradores de sistemas e de bancos de dados preferirão usar o WACA para verificar as configurações do IIS, do SQL e do sistema (veja a Figura 1). Ao todo existem mais de 140 verificações no WACA derivadas de requisitos e padrões do SDL, e diretrizes de codificação de práticas.

image: Web Application Configuration Analyzer Rules

Figura 1 Regras do Web Application Configuration Analyzer

Um recurso realmente mais útil do WACA é que você pode criar automaticamente itens de trabalho ou bugs em projetos de equipe do Team Foundation Server (TFS) a partir dos resultados da verificação do WACA. Isso é útil especialmente quando você o utiliza com um projeto de equipe criado a partir do modelo de processo SDL ou do modelo de processo MSF-Agile+SDL. Na página de configuração do WACA TFS, mapeie o campo de modelo “Origin” (Origem) para o valor “Web Application Configuration Analyzer.” Agora, quando você exibir os relatórios de bugs e os gráficos de tendências, poderá filtrar e fazer busca detalhada nos resultados do WACA para ver a sua eficiência na detecção de vulnerabilidades potenciais (veja a Figura 2).

image: WACA Team Foundation Server Integration

Figura 2 Integração do WACA Team Foundation Server

Leia mais sobre o WACA na página do grupo de segurança da informação de TI da Microsoft (msdn.microsoft.com/security/dd547422); assista a um vídeo de demonstração da ferramenta apresentado por Anil Revuru, gerente de programas do projeto WACA (msdn.microsoft.com/security/ee909463); ou, melhor ainda, baixe a ferramenta e experimente-a você mesmo (tinyurl.com/3x7bgfd).

Sempre verifique as suas configurações

É frustrante pensar que você poderia desenvolver o seu aplicativo seguindo cada diretriz de desenvolvimento seguro e melhor prática, e ainda assim acabar invadido por causa de um erro simples em um arquivo de configuração web.config. Ainda mais frustrante é perceber que os arquivos web.config são criados para serem alterados a qualquer momento e que o erro de configuração pode aparecer anos após você ter concluído a codificação do aplicativo e tê-lo movido para produção. É importante verificar sempre as suas configurações — não só por meio de inspeção manual, como também usando ferramentas automatizadas, e não só durante o ciclo de vida de desenvolvimento, mas também na produção.

Acompanhe os ataques de DoS de expressão regular

Em um tópico completamente diferente: na coluna Informativos sobre segurança de maio de 2010 (msdn.microsoft.com/magazine/ff646973), eu escrevi sobre o ataque de DoS de expressão regular demonstrado por Checkmarx na conferência da OWASP em Israel, em setembro de 2009. Nessa coluna, também forneci o código para um fuzzer de DoS de expressão regular baseado na funcionalidade Plano de geração de dados de projetos de banco de dados do Visual Studio. Embora essa abordagem tenha sido tecnicamente segura e tenha funcionado bem para detectar vulnerabilidades de expressão regular, ela foi reconhecidamente um tanto maçante para gerar os dados de teste, e era necessário ter uma licença do Visual Studio Database Projects. Portanto, tenho a satisfação de informar que a equipe do SDL lançou uma nova ferramenta que pode ser baixada gratuitamente, para fuzzing de vulnerabilidades de expressão regular, e que cuida dos detalhes da geração de dados para você. A ferramenta não possui dependências externas (além do .NET Framework 3.5). Ela é mostrada na Figura 3.

image: SDL Regex Fuzzer

Figura 3 SDL Regex Fuzzer

Você pode baixar o SDL Regex Fuzzer em microsoft.com/sdl. Experimente e nos dê a sua opinião.      

Bryan Sullivan é gerente de programas de segurança da equipe do Ciclo de Vida do Desenvolvimento da Segurança da Microsoft, onde atua como especialista em problemas de segurança de aplicativos Web e do Microsoft .NET Framework. É autor do livro “Ajax Security” (Addison-Wesley, 2007).

Agradecemos ao seguinte especialista técnico pela revisão deste artigo: Anil Revuru