c
| Por Luciano Caixeta Moreira luciano.caixeta@braziltradenet.gov.br Luciano Caixeta é desenvolvedor .NET e possui as certificações MCSD .NET, MCDBA e MCT. Luciano mantém um blog no TheSpoke em http://br.thespoke.net/MyBlog/Luti/MyBlog.aspx. |
|
|
|
|
| Limite de upload com ASP.NET e ataque de DOS | |
|
|
|
É comum encontrarmos sites que oferecem espaço de armazenamento juntamente com a funcionalidade de gerenciamento de documentos, onde é possível que o usuário faça upload de arquivos para o servidor.
Com o Microsoft .NET, implementar uma página web que faz upload de arquivos é simples, basta criarmos um formulário com o atributo encType = "multipart/form-data", uma entrada de arquivos - <input type="file" id="btnArquivo" ... - e no postback de um botão o arquivo enviado pode ser recuperado através da instrução btnArquivo.PostedFile.SaveAs(...).
Agora, algumas considerações sobre o assunto.
Limitando o tamanho dos arquivos enviados
Durante as pesquisas realizadas, não foi encontrada nenhuma referência para o limite de tamanho dos arquivos que o internet explorer pode enviar, então foi possível pressupor que este controle deveria ser feito pelo framework .NET.
O arquivo de configuração machine.config possui o elemento httpRuntime que limita o tamanho máximo da requisição através do atributo maxRequestLength (em Kbytes). A configuração padrão do framework define que o tamanho máximo de uma requisição http é de 4.096 KB.
Estrutura completa do elemento:
<httpRuntime executionTimeout="90" maxRequestLength="4096" useFullyQualifiedRedirectUrl="false" minFreeThreads="8" minLocalRequestFreeThreads="4" appRequestQueueLimit="100" enableVersionHeader="true"/>
Para alterar o limite máximo da requisição na página de upload, deve-se sobrepor a configuração do framework através do arquivo web.config da aplicação ou um novo arquivo web.config criado na pasta aonde se encontra o aspx. A estrutura do elemento XML deve seguir o seguinte modelo:
<configuration>
<location path="frmGerenciadorArquivos.aspx">
<system.web>
<httpRuntime maxRequestLength="5120" />
</system.web>
</location>
</configuration>
O atributo path indica o local da página aspx de upload e o maxRequestLength indica que agora o tamanho máximo da requisição é de 5MB.
Upload de arquivos pelo IIS
* Aspecto de implementação do envio de arquivos através do browser: o IIS progressivamente armazena em memória os bytes do arquivo enviados, até que todo o upload seja concluído e a requisição completada.
Isso possibilita o caso de 50 usuários enviarem arquivos de 5MB em um intervalo de tempo curto, fazendo com que em um determinado momento quase 250MB de memória sejam consumidos somente pelos bytes dos arquivos de upload. A figura 01 exemplifica um possível cenário.
Figura
01
Ataque de negação de serviço (Denial of Service - DOS)
A configuração padrão do framework é utilizar no máximo 60% da memória física disponível antes de reciclar o processo. Essa configuração pode ser vista no arquivo machine.config através do elemento processModel.
<processModel enable="true" ... memoryLimit="60" ... />
Isto significa que em uma máquina com 512 MB de memória, aproximadamente 307 MB estão disponíveis para um processo, como é o caso do aspnet_wp.exe. Quando este limite é alcançado, uma mensagem de Server Application Unavailable aparece para o usuário e o processo é reciclado.
Para verificar o limite de memória, foi utilizado o contador de performance "process > private bytes" para monitorar o processo aspnet_wp.exe e um teste de carga foi executado. No teste o limite máximo da requisição foi alterado para 150MB e simultaneamente foram disparados uploads de quatro arquivos de 100MB. Em um determinado momento o limite de 307 MB estoura, gerando a queda brusca demonstrada pela figura 02.

Figura 02
Ps: também foi monitorada a coleção de lixo das gerações 0,1 e 2. Enquanto o consumo de memória vai aumentando, o ambiente de execução do .NET tenta loucamente liberar mais espaço através de coletas de lixo, mas como as referências aos arquivos estão sendo utilizadas e não podem ser liberadas, não existe nada que o CLR possa fazer para impedir que o limite de memória seja alcançado.
Mas qual a relação entre o limite de upload, a memória do servidor e o ataque de negação de serviço?
Quanto maior o tamanho permitido das requisições, maior a probabilidade de existirem uploads simultâneos e maiores, consumindo uma grande quantidade de memória do servidor e causando a falha do serviço.
Um atacante pode utilizar esse comportamento para simular muitas requisições com upload de grandes arquivos em loops eternos, fazendo com que o servidor fique atolado e pare de atender outras requisições.
A configuração padrão do framework tenta impedir este problema, limitando o tamanho da requisição em 4 MB e controlando o número máximo de threads que atendem as requisições e a fila de espera.
Mais informações sobre o limite de upload em: Cannot Upload Large Files When You Use the HtmlInputFile Server Control
O arquivo Upload.zip contém um projeto ASP.NET/VB.NET que mostra como executar o upload e alterar a configuração padrão do framework através de arquivos de configuração (web.config).