FNSP Web Page

Aceitar ficheiros de estranhos sem levar com um susto

Um formulário de upload é um convite para pôr ficheiros no seu servidor. Vale a pena aceitar com regras.

1. A extensão não prova nada

Mudar virus.php para foto.jpg demora um segundo. O que se verifica é o conteúdo: os primeiros bytes de um ficheiro dizem o que ele é.

// Assinaturas: os primeiros bytes de cada formato
const ASSINATURAS = {
  'image/jpeg': [0xff, 0xd8, 0xff],
  'image/png': [0x89, 0x50, 0x4e, 0x47],
  'application/pdf': [0x25, 0x50, 0x44, 0x46],
};

const cabeca = new Uint8Array(await ficheiro.slice(0, 4).arrayBuffer());
const tipo = Object.entries(ASSINATURAS).find(([, assinatura]) =>
  assinatura.every((byte, i) => cabeca[i] === byte)
);

if (!tipo) throw new Error('Formato não aceite.');

O Content-Type que vem no pedido também não prova nada: quem envia é que o escreve.

2. Um limite de tamanho, antes de ler

Sem limite, um ficheiro de 40 GB enche o disco ou a memória. O limite tem de estar no servidor e no proxy à frente — o do browser é uma sugestão.

client_max_body_size 10M;

3. O nome do ficheiro é do atacante

Nunca use o nome que vem no pedido. Ele pode conter ../ e escrever fora da pasta pretendida, ou ter 300 caracteres, ou chamar-se .htaccess.

import { randomUUID } from 'node:crypto';

const nome = `${randomUUID()}.jpg`; // o nome original guarda-se na base, se interessar

4. Onde os ficheiros ficam

  • Fora da pasta servida pelo site. Se estiverem num sítio que o servidor web serve diretamente, um ficheiro com o nome certo pode acabar por ser executado.

  • Servidos por uma rota que verifica permissões, ou por um armazenamento externo com endereços assinados e validade curta.

  • Com o cabeçalho certo à saída, para o browser não adivinhar: Content-Type correto e X-Content-Type-Options: nosniff.

5. Imagens não são inofensivas

Um SVG é XML, e XML pode ter JavaScript lá dentro — um SVG servido do seu domínio é um XSS. Ou se recusa o formato, ou se sanitiza como se sanitiza HTML. E vale a pena reprocessar as imagens aceites: além de as normalizar, isso deita fora os metadados EXIF, que costumam trazer as coordenadas GPS de onde a fotografia foi tirada.

Comentários

Ainda ninguém comentou este artigo.

Voltar ao blog

Gostávamos de saber quantas pessoas visitam o site, com o Google Analytics. Sem a sua autorização não corre nada. Política de Privacidade.