Blog · Publicado originalmente em inglês a .
Um ficheiro ZIP não é só um monte de dados. São instruções de um desconhecido sobre onde escrever ficheiros e quanta memória usar, e todas as bibliotecas de descompressão, por predefinição, obedecem-lhes.
Nomes que saem da pasta
Uma entrada pode chamar-se ../../etc/passwd. Se alguma coisa juntar isso a uma pasta, vai parar a um lugar que ninguém pretendia. É um problema antigo, que tem até nome, zip slip, e o conselho habitual é limpar o caminho.
Nós preferimos recusar. Estes nomes tornam-se endereços na própria origem do site, e um nome que teríamos de limpar é um nome que não percebemos. Limpar transforma uma entrada hostil numa entrada plausível. Recusar transforma-a numa mensagem que diz qual ficheiro era o problema.
Ficheiros pequenos que não são pequenos
Quarenta kilobytes podem transformar-se em quatro gigabytes ao descomprimir. A verificação óbvia, descomprimir e depois ver o tamanho, acontece quando a memória já se esgotou.
Por isso, todas as decisões sobre tamanho são tomadas com base nos tamanhos declarados nos próprios cabeçalhos do ZIP, antes de expandir um único byte: o total, cada ficheiro, o número de ficheiros e a proporção entre comprimido e descomprimido. Um ficheiro de quatro megabytes só com zeros fica com menos de sessenta e quatro kilobytes comprimido, e é recusado só por essa proporção.
Os tamanhos declarados também são a palavra de um desconhecido, claro. Mas é uma palavra que se pode verificar com pouco custo, e que só nos causa problemas se declarar menos do que há. E isso a leitura em streaming deteta pelo caminho.
Uma lista do que entra, não do que fica de fora
As extensões que servimos estão numa lista. Tudo o resto é recusado pelo nome, com a extensão na mensagem, para que a pessoa saiba que ficheiro retirar.
Uma lista do que fica de fora seria a promessa de ter pensado em tudo. Não pensámos, nem ninguém pensou. Um alojamento estático que serve .php não é um alojamento estático, e a forma de ter a certeza é dizer o que entra, e não o que fica de fora.
A parte que não era sobre segurança
As pessoas comprimem uma pasta, por isso tudo chega dentro de uma pasta que ninguém queria no endereço. Uma única pasta comum na raiz é retirada. Duas ou mais significam que o ZIP está mesmo organizado assim, e ficam como estão.
E uma pasta sem index.html era um erro. Não é: uma pasta de imagens, ou um relatório e a sua folha de cálculo, é uma coisa perfeitamente razoável de querer num link. Escrevemos nós a página em que abre: uma lista do que está lá dentro, com todos os nomes escapados, porque esses nomes vieram de um desconhecido e a página é servida a partir da própria origem do site.
Os testes parecem uma lista do que o ZIP de um desconhecido não tem autorização para dizer. Foi a forma mais útil que encontrámos para eles.
Perguntas
O que acontece a um ZIP que tem um nome que sai da pasta?
É recusado. O Solta não limpa o caminho: recusa, com uma mensagem que diz qual ficheiro era o problema.
Como é que o Solta lida com um ZIP pequeno que se transforma em gigabytes ao descomprimir?
Todas as decisões sobre tamanho usam os tamanhos declarados nos cabeçalhos do próprio ZIP, antes de expandir um único byte: o total, cada ficheiro, o número de ficheiros e a proporção entre comprimido e descomprimido. Se o ZIP declarar menos do que há, a leitura em streaming deteta-o pelo caminho.
Que tipos de ficheiro de um ZIP são publicados?
Só as extensões que estão numa lista. Tudo o resto é recusado pelo nome, com a extensão na mensagem, para que se saiba que ficheiro retirar.
Porque é que a pasta de fora não aparece no endereço?
Quem comprime uma pasta faz tudo chegar dentro dela. Uma única pasta comum na raiz é retirada. Se houver duas ou mais, o ZIP está mesmo organizado assim, e ficam como estão.
Uma pasta sem index.html pode ser publicada?
Pode. O Solta escreve a página em que abre: uma lista do que está lá dentro, com todos os nomes escapados.

