Arquivos TAR aparecem em backups, pacotes de software, pipelines de dados, imagens de contêineres e processos de implantação. O módulo tarfile do Python facilita a leitura e a extração desses arquivos, mas extrair conteúdo vindo de uma fonte externa exige cuidado. Um arquivo malicioso pode tentar gravar dados fora da pasta de destino, criar links perigosos, alterar permissões ou sobrescrever arquivos importantes. O recurso extraction_filter existe para tornar esse processo mais explícito e seguro.
Neste guia, você aprenderá como usar filtros de extração, como escolher uma política adequada, como criar um filtro personalizado e quais verificações devem ser feitas antes de aceitar um arquivo TAR em produção.
Por que a extração de TAR exige validação
Um membro de arquivo TAR possui nome, caminho, tipo, permissões, usuário, grupo, tamanho e, em alguns casos, destino de link. Esses metadados podem ser manipulados. Um nome como ../../config.php tenta escapar da pasta de destino. Um caminho absoluto pode apontar diretamente para uma área sensível do sistema. Links simbólicos também podem redirecionar a escrita para fora do diretório esperado.
Por isso, nunca trate um TAR desconhecido como se fosse apenas uma coleção inocente de arquivos. A extração deve ser uma operação controlada, com destino isolado, limites de tamanho, política de nomes e revisão dos tipos permitidos.
O papel de extraction_filter
O atributo TarFile.extraction_filter permite definir uma política aplicada aos membros durante a extração. O filtro recebe informações sobre o membro e pode aceitar, modificar ou rejeitar a entrada. Em vez de espalhar verificações manuais pelo código, você centraliza a política em um ponto claro e reutilizável.
O Python oferece filtros conhecidos, como políticas mais permissivas para compatibilidade e políticas mais restritivas para dados comuns. Em aplicações modernas, a escolha deve favorecer a opção mais segura compatível com o seu caso de uso.
from pathlib import Path
import tarfile
arquivo = Path("backup.tar.gz")
destino = Path("dados_extraidos")
destino.mkdir(parents=True, exist_ok=True)
with tarfile.open(arquivo, "r:gz") as tar:
tar.extractall(destino, filter="data")
O filtro data é uma escolha adequada quando o objetivo é extrair arquivos de dados comuns e evitar características perigosas ou desnecessárias de um arquivo de sistema completo.
Filtro data, tar e fully_trusted
A política data tenta produzir uma extração apropriada para dados, removendo ou recusando aspectos arriscados. A política tar preserva mais características tradicionais do formato. Já fully_trusted representa uma postura permissiva e só deve ser considerada quando a origem é realmente confiável e o arquivo foi produzido dentro de um ambiente controlado.
Na prática, prefira data para uploads, integrações, downloads e arquivos recebidos de terceiros. Use opções mais permissivas apenas quando houver uma necessidade técnica clara, revisão do conteúdo e isolamento suficiente.
Criando um filtro personalizado
Alguns projetos precisam aceitar apenas arquivos regulares, impedir executáveis ou limitar extensões. Um filtro personalizado permite expressar essas regras.
from pathlib import Path
import tarfile
EXTENSOES = {".csv", ".json", ".txt"}
def filtro_dados(member, path):
nome = Path(member.name)
if member.isdir():
return member
if not member.isfile():
return None
if nome.suffix.lower() not in EXTENSOES:
return None
if member.size > 20 * 1024 * 1024:
return None
return member.replace(mode=0o600)
with tarfile.open("entrada.tar") as tar:
tar.extractall("saida", filter=filtro_dados)
Nesse exemplo, diretórios são aceitos, arquivos especiais são descartados, apenas três extensões são permitidas, cada arquivo deve ter no máximo 20 MB e as permissões são normalizadas. A função retorna None quando o membro deve ser ignorado.
Verifique o tamanho total
Limitar apenas o tamanho individual não impede um arquivo composto por milhares de entradas pequenas. Antes de extrair, some os tamanhos declarados e imponha um limite total. Também defina um número máximo de membros.
MAX_ARQUIVOS = 5000
MAX_TOTAL = 500 * 1024 * 1024
with tarfile.open("entrada.tar") as tar:
membros = tar.getmembers()
if len(membros) > MAX_ARQUIVOS:
raise ValueError("Muitos arquivos no TAR")
total = sum(m.size for m in membros if m.isfile())
if total > MAX_TOTAL:
raise ValueError("Tamanho total excedido")
tar.extractall("saida", members=membros, filter="data")
Esses limites ajudam a reduzir risco de esgotamento de disco, memória e tempo de processamento.
Extraia em diretório isolado
Evite extrair diretamente em uma pasta usada pela aplicação. Crie um diretório temporário, faça a validação e mova apenas os arquivos aprovados para o destino final. Esse fluxo reduz o impacto de nomes inesperados e evita misturar dados incompletos com arquivos ativos.
Depois da extração, percorra o diretório resultante, confirme os tipos, valide o conteúdo e registre métricas. Para dados estruturados, tente abrir e analisar cada arquivo antes de promovê-lo.
Links simbólicos e hard links
Links merecem atenção especial porque o caminho aparente pode ser seguro enquanto o destino aponta para outro local. Quando o projeto não precisa de links, rejeite todos. Essa política simples elimina uma classe importante de problemas.
def sem_links(member, path):
if member.issym() or member.islnk():
return None
return tarfile.data_filter(member, path)
Você pode combinar sua própria regra com um filtro padrão. Assim, aproveita a proteção existente e adiciona as restrições específicas do projeto.
Tratamento de erros
Não ignore exceções de extração. Registre o nome do arquivo, a etapa, o motivo da rejeição e o identificador da operação. Porém, não exponha caminhos internos ou detalhes sensíveis ao usuário final.
import tarfile
try:
with tarfile.open("entrada.tar") as tar:
tar.extractall("saida", filter="data")
except tarfile.TarError as erro:
raise RuntimeError("Arquivo TAR inválido ou inseguro") from erro
Também remova o diretório temporário quando a operação falhar, evitando resíduos e resultados parciais.
Boas práticas para produção
Use listas de permissões de extensões, imponha limites individuais e totais, rejeite arquivos especiais, normaliza permissões, extraia em área temporária e mantenha logs. Execute a extração com um usuário sem privilégios e, para cargas não confiáveis, considere um contêiner ou processo isolado.
Não use apenas a extensão do TAR para decidir se ele é seguro. Valide o formato, o conteúdo e o contexto. Um arquivo com nome correto ainda pode ter metadados perigosos.
Compatibilidade entre versões
Ao manter bibliotecas compatíveis com diferentes versões do Python, teste se o parâmetro filter está disponível e documente o comportamento mínimo aceito. Evite criar uma falsa sensação de segurança em ambientes antigos. Se a aplicação depende dessa proteção, estabeleça uma versão mínima do Python.
Testes recomendados
Crie testes com caminhos relativos normais, caminhos com .., caminhos absolutos, links, arquivos grandes, muitos membros, extensões bloqueadas e permissões incomuns. Confirme que o diretório final permanece vazio quando a validação falha.
Você também pode revisar outros conteúdos da Academify sobre zipfile.Path no Python, os.path.splitroot, pathlib.Path.info e sqlite3 autocommit. Para referência oficial, consulte a documentação do tarfile e as orientações do pathlib.
Conclusão
tarfile extraction_filter transforma a extração em uma operação governada por política. Em vez de confiar cegamente nos metadados do arquivo, você decide quais membros, caminhos, tamanhos, tipos e permissões são aceitáveis. Para a maioria dos arquivos externos, comece com filter="data", adicione limites e use um diretório temporário. Essa combinação oferece uma base muito mais segura e previsível para processar TAR no Python.







