O maior portal de MU Online do Brasil — desde 2003
Tutorial Avançado Web

Como sanitizar uploads de usuário no site e painel do seu servidor de MU Online

Implemente sanitização segura de uploads de usuário (avatares, anexos de ticket, imagens de fórum) no site do seu servidor de MU Online, cobrindo validação de tipo real, limite de tamanho, renomeação e armazenamento fora da webroot.

GA Gabriel · Atualizado em 2 nov 2025 · ⏱ 16 min de leitura
Resposta rápida

O site e o painel de um servidor de MU Online quase sempre aceitam algum tipo de upload de usuário — avatar de perfil, anexo de ticket de suporte, imagem de post no fórum da comunidade. Cada um desses pontos de entrada é, sem o tratamento correto, uma porta aberta para upload de webshell, defacement

O site e o painel de um servidor de MU Online quase sempre aceitam algum tipo de upload de usuário — avatar de perfil, anexo de ticket de suporte, imagem de post no fórum da comunidade. Cada um desses pontos de entrada é, sem o tratamento correto, uma porta aberta para upload de webshell, defacement do site ou comprometimento total do servidor web. Este tutorial cobre a sanitização de uploads de forma completa: validação de tipo real, limites de tamanho, renomeação segura, armazenamento fora da webroot e reprocessamento de imagens, com exemplos práticos em PHP, a linguagem mais comum em painéis de servidores de MU.

Por que upload de arquivo é um dos vetores de ataque mais comuns

Painéis de servidores de MU Online são frequentemente construídos rapidamente, com foco em funcionalidade (ranking, loja, votação) e pouca atenção a segurança de upload. Um campo de "enviar avatar" ou "anexar print no ticket" mal validado permite que um atacante envie um arquivo .php disfarçado de imagem e, se esse arquivo cair em uma pasta pública com permissão de execução, ele ganha execução de código diretamente no servidor — o pior cenário possível, pior até que uma injeção SQL isolada, porque dá controle total da máquina.

O erro fundamental: confiar na extensão do arquivo

A validação mais comum e mais falha em painéis é checar apenas a extensão do nome do arquivo enviado. Um atacante pode nomear o arquivo shell.php.jpg, manipular o campo MIME type enviado pelo navegador (que é controlado pelo cliente, portanto não confiável), ou usar técnicas de duplo unicode para burlar filtros ingênuos. A extensão do nome do arquivo é metadado, não prova do conteúdo real.

Validando o tipo real do arquivo pelo conteúdo (magic bytes)

A validação confiável verifica os primeiros bytes do arquivo (assinatura binária), não o nome nem o cabeçalho MIME enviado pelo cliente. Em PHP, a função finfo_file (extensão Fileinfo) lê o conteúdo real do arquivo:

<?php
function validarTipoReal(string $caminhoTemp, array $tiposPermitidos): bool {
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeReal = finfo_file($finfo, $caminhoTemp);
    finfo_close($finfo);

    return in_array($mimeReal, $tiposPermitidos, true);
}

$tiposPermitidos = ['image/jpeg', 'image/png', 'image/webp'];
if (!validarTipoReal($_FILES['avatar']['tmp_name'], $tiposPermitidos)) {
    http_response_code(400);
    exit('Tipo de arquivo não permitido.');
}

Essa checagem deve ser a primeira barreira, antes de qualquer outra validação, porque ela impede que um arquivo com payload disfarçado de imagem chegue às etapas seguintes do processamento.

Limitando o tamanho do arquivo

Além do limite configurado no PHP (upload_max_filesize, post_max_size), valide o tamanho explicitamente no código da aplicação, porque limites de servidor mal configurados ou ausentes em ambientes de desenvolvimento não protegem produção sozinhos.

Tipo de uploadLimite recomendadoRacional
Avatar de perfil200KB – 1MBImagem pequena, sem necessidade de alta resolução
Anexo de ticket de suporte2–5MBCobre prints e logs de erro comuns
Imagem de post de fórum1–3MBEquilíbrio entre qualidade e espaço em disco
Banner/imagem de guild (se houver)500KB – 2MBUso decorativo, não precisa de arquivo pesado
<?php
$limiteBytes = 1 * 1024 * 1024; // 1MB para avatar
if ($_FILES['avatar']['size'] > $limiteBytes) {
    http_response_code(400);
    exit('Arquivo excede o tamanho máximo permitido.');
}

Renomeando o arquivo no momento do salvamento

Nunca preserve o nome original enviado pelo usuário. Nomes como ../../../var/www/config.php (path traversal) ou nomes duplicados entre usuários diferentes são riscos reais. Gere um identificador novo, geralmente um hash ou UUID, e associe a extensão validada (não a extensão original do envio):

<?php
$extensaoSegura = match ($mimeReal) {
    'image/jpeg' => 'jpg',
    'image/png' => 'png',
    'image/webp' => 'webp',
    default => throw new RuntimeException('Tipo não suportado.'),
};

$nomeFinal = bin2hex(random_bytes(16)) . '.' . $extensaoSegura;

Armazenando uploads fora da webroot

Mesmo com validação rigorosa, a defesa em profundidade recomenda salvar os arquivos enviados fora da pasta pública do servidor web (webroot), ou em uma pasta configurada explicitamente sem permissão de execução de scripts. Se um arquivo malicioso escapar de todas as validações, ele ainda não conseguirá ser executado diretamente por URL.

Estrutura recomendada:
/var/www/muweb/           <- webroot pública (Apache/Nginx aponta aqui)
/var/data/uploads/         <- fora da webroot, uploads reais ficam aqui
/var/www/muweb/serve.php   <- script que lê de /var/data/uploads/ e entrega a imagem

O serve.php (ou rota equivalente) lê o arquivo do diretório protegido e o entrega ao navegador com o Content-Type correto, sem nunca expor o caminho real de armazenamento nem permitir que o arquivo seja acessado como script.

Configurando o servidor web para negar execução na pasta de upload

Como camada adicional, mesmo que uploads fiquem dentro da webroot por alguma limitação de infraestrutura, desative a execução de scripts nessa pasta especificamente. Em Apache, via .htaccess na pasta de uploads:

<FilesMatch "\.(php|php5|phtml|pl|py|cgi|sh)$">
    Require all denied
</FilesMatch>

Em Nginx, o equivalente é garantir que o bloco de location da pasta de uploads não repasse arquivos para o processador PHP-FPM, servindo-os apenas como estáticos.

Reprocessando imagens para remover payloads escondidos

Uma técnica conhecida de ataque usa "imagens polimórficas" — arquivos que são simultaneamente um .jpg válido e um script válido, dependendo de como são interpretados. Reabrir a imagem com uma biblioteca de processamento e salvá-la novamente (mesmo sem alterar a qualidade visual) reconstrói o arquivo do zero, eliminando qualquer payload embutido fora da estrutura padrão da imagem:

<?php
function reprocessarImagem(string $origem, string $destino, string $mime): void {
    $imagem = match ($mime) {
        'image/jpeg' => imagecreatefromjpeg($origem),
        'image/png' => imagecreatefrompng($origem),
        'image/webp' => imagecreatefromwebp($origem),
    };

    match ($mime) {
        'image/jpeg' => imagejpeg($imagem, $destino, 85),
        'image/png' => imagepng($imagem, $destino),
        'image/webp' => imagewebp($imagem, $destino, 85),
    };

    imagedestroy($imagem);
}

Aplicando as mesmas regras a anexos que não são imagem

Anexos de ticket de suporte às vezes precisam aceitar outros formatos (PDF, texto de log). Para esses casos, a validação de magic bytes continua válida, mas a defesa em profundidade ganha ainda mais importância — nunca sirva um PDF ou arquivo de texto enviado por usuário a partir de uma pasta com permissão de execução, e considere adicionar o cabeçalho Content-Disposition: attachment ao servir esses arquivos, forçando o download em vez da renderização inline no navegador.

Registrando e limitando a taxa de uploads

Além da validação de conteúdo, limite quantos uploads uma conta pode fazer em um intervalo de tempo (ex.: 10 uploads por hora) para mitigar abuso de armazenamento e tentativas automatizadas de bypass por força bruta de variações de payload. Registrar metadados de cada upload (conta, IP, hash do arquivo, resultado da validação) também ajuda a identificar contas comprometidas ou comportamento de bot rapidamente.

Erros comuns e soluções

SintomaCausa provávelSolução
Arquivo .php disfarçado passa na validaçãoChecagem só pela extensão ou MIME enviado pelo clienteValide pelo conteúdo real (magic bytes) com Fileinfo
Upload executado diretamente via URLArquivo salvo em pasta pública com execução habilitadaArmazene fora da webroot e sirva via script intermediário
Colisão de nomes ou path traversalNome original do usuário preservado no salvamentoGere nome novo (hash/UUID) e extensão validada
Imagem com payload escondido mesmo após validaçãoAusência de reprocessamento da imagemReabra e salve novamente com GD/Imagick
Abuso de espaço em disco com uploads repetidosFalta de limite de tamanho e de taxa por contaImplemente limite de tamanho e rate limiting por conta/IP

Checklist de sanitização de uploads

  • Validação de tipo real por magic bytes implementada (não apenas extensão/MIME do cliente).
  • Limite de tamanho definido por tipo de upload (avatar, ticket, fórum).
  • Arquivos renomeados com hash/UUID no momento do salvamento.
  • Uploads armazenados fora da webroot ou em pasta sem permissão de execução.
  • Servidor web configurado para negar execução de script na pasta de uploads.
  • Imagens reprocessadas (GD/Imagick) antes do armazenamento final.
  • Rate limiting e log de uploads por conta/IP implementados.

Com os uploads sanitizados, revise também os demais pontos de entrada de dados do seu painel — o tutorial de criação de servidor de MU Online cobre a base de infraestrutura sobre a qual essas proteções devem ser aplicadas.

Perguntas frequentes

Validar a extensão do arquivo já é suficiente para segurança?

Não. Validar apenas a extensão (.jpg, .png) é uma das falhas mais exploradas em painéis de servidores de MU Online, porque um atacante pode renomear um arquivo .php para .jpg.php ou manipular o cabeçalho para burlar essa checagem. É preciso validar o tipo real do arquivo pelo conteúdo binário (magic bytes), não pelo nome.

Por que não devo salvar uploads dentro da pasta pública do site?

Porque se um arquivo malicioso escapar da validação e ficar em uma pasta acessível publicamente (ex.: /public/uploads/), o atacante pode executá-lo diretamente pela URL. Salvar uploads fora da webroot, ou em uma pasta sem permissão de execução de script, é uma camada de defesa essencial mesmo se a validação falhar.

Preciso reprocessar imagens depois do upload?

É altamente recomendado. Reabrir a imagem com uma biblioteca de processamento (como GD ou Imagick em PHP) e salvá-la novamente remove metadados maliciosos e payloads escondidos em arquivos de imagem polimórficos (imagem+script), uma técnica comum para burlar validações superficiais.

Qual o limite de tamanho recomendado para avatares e anexos de ticket?

Para avatares, algo entre 200KB e 1MB já é suficiente e evita abuso de armazenamento; para anexos de ticket de suporte, um limite de 2-5MB cobre a maioria dos casos legítimos (print de erro, log). Limites generosos demais abrem espaço para abuso de espaço em disco e ataques de negação de serviço por upload.

Renomear o arquivo enviado pelo usuário é realmente necessário?

Sim, é uma prática essencial. Manter o nome original do arquivo expõe o servidor a path traversal (nomes como ../../config.php) e a colisão de nomes entre usuários. Gerar um nome novo (hash ou UUID) no momento do salvamento elimina os dois riscos de uma vez.

GA
Editor de guias e builds

Gabriel cobre gameplay, builds de classes, PvP e progressão. Testa cada estratégia em servidor antes de publicar.

Continue lendo

Artigos relacionados