Caixa De Areia Fechada - ChezMax Caixa de areia fechada para gatos com caixa de areia para gatos ...
ChezMax Caixa de areia fechada para gatos com caixa de areia para gatos ...

O que é e quando você realmente precisa disso

Caixa de areia fechada é um ambiente isolado de execução onde o código roda com restrições intencionais de acesso ao sistema, rede e recursos. Não é um contêiner Docker completo. Não é uma VM. É algo entre um processo em chroot e um contêiner com cgroups, mas configurado de forma mais restritiva do que o padrão. A ideia básica: você dá permissão para a aplicação fazer exatamente o que ela precisa e bloqueia todo o resto. A maioria dos desenvolvedores que encontro usando isso está lidando com processamento de upload de usuário, execução de scripts maliciosos ou desconhecidos, ou testes de software antes de liberar para produção. Tem gente que também usa pra rodar código de terceiros em pipeline CI sem que um pacote quebrado derrube o servidor inteiro.

Caixa de areia fechada na prática

O setup mais comum envolve Linux com namespaces, AppArmor ou SELinux, e configuração de seccomp. Você cria um namespace de mount pra que o processo não veja o sistema de arquivos real, limita os dispositivos de bloco e caractere acessíveis, e define regras de rede — ou simplesmente corta a saída. Depois adiciona um perfil AppArmor que proíbe escrita fora de um diretório específico. O tempo de setup inicial varia muito. Se você começar do zero, leva cerca de 3 a 5 horas para montar algo que funcione de verdade. Se já tiver uma base de contêineres, cai para uns 40 minutos. Um problema que eu enfrentei recentemente foi com um processo que precisava de acesso a /dev/null e /dev/urandom, mas o perfil seccomp padrão estava bloqueando openat() nesses caminhos porque a regra geral negava todos os acessos a /dev. A solução foi adicionar regras explícitas de permissão apenas para esses dois devices, usando syscall filter Whitelist ao invés de. Tentar permitir tudo do /dev é um erro comum e é exatamente o tipo de coisa que faz a sandbox escapar se você não prestar atenção nos points de montagem.

Implementação passo a passo

Comece decidindo o nível de isolamento. Sandbox nível 1: processo único sem rede, com mount namespace isolado. Nível 2: adiciona user namespace, limitar syscalls com seccomp-bpf. Nível 3: perfil AppArmor ou SELinux com política restrita, controle de CGroups para CPU e memória. Nível 4: namespace de network completamente isolado, apenas bridges controladas. Para o nível 1, que é onde a maioria das pessoas deve começar, você pode usar unshare com as flags corretas. Um comando básico seria algo como unshare --mount --pid --fork --propagation private, depois entrar com chroot no diretório preparado. Mas só isso não é suficiente. Você precisa configurar um sistema de arquivos root que contenha apenas o que o processo vai usar — libc, binários essenciais, as bibliotecas da aplicação. Um rootstrap feito com debootstrap ou uma imagem minimalista resolve.

No nível 2, a parte do seccomp é onde a coisa fica séria. Você vai precisar de uma biblioteca como libseccomp ou compilar um filtro BPF manual. O truque aqui é começar com uma lista branca de syscalls permitidos. Para a maioria das aplicações, você precisa de read, write, openat, close, mmap, munmap, brk, exit, futex, epoll_create, clone, execve — e dependendo do que a app faz, talvez access, stat, ioctl. Qualquer syscall fora dessa lista é negado com errno como ENOSYS. Eu recomendo usar scmp_filter_ctx do libseccomp em vez de tentar montar filtros BPF na mão, a menos que você tenha motivo específico pra não usar a biblioteca. Para o nível 3 com AppArmor, o perfil é definido num arquivo de texto. Um exemplo mínimo pra uma sandbox que só precisa ler e escrever num diretório /app/data seria:

@{ROOT}=/opt/sandbox deny @{ROOT}/r,

writing @{ROOT}/data/, deny / w,

👉 Clique no botão abaixo para saber mais sobre o assunto!

deny /proc/ w, deny /sys/ rw,

network inet stream, network inet dgram.

Isso bloqueia escrita em praticamente tudo exceto o diretório designado e corta a maioria dos acessos ao proc e sysfs. A linha de network depende do que sua aplicação precisa. Se ela não precisa de rede, remova ambas. O nível 4 envolve iptables ou nftables pra controlar tráfego de saída. Regras básicas: DROP tudo por padrão, ACCEPT apenas para DNS (porta 53 UDP/TCP) e HTTPS (porta 443 TCP) se a aplicação precisar de internet. Isso evita que dados vazem e impede conexões de saída maliciosas.

Testando se a sandbox funciona

Antes de colocar em produção, você precisa testar se o processo consegue sair da caixa. Um teste simples: dentro da sandbox, rode um programa que tenta abrir /etc/shadow. Deve falhar. Tente wget para um host externo. Deve falhar se a rede estiver cortada. Tente escrever em /tmp. Deve falhar se o mount namespace estiver correto. Tente usar ptrace em outro processo. Deve falhar se o namespace de PID estiver isolado. Eu já vi casos onde a sandbox parecia funcional mas o processo conseguia escapar porque o usuário tinha sido mapeado como uid 0 dentro do user namespace, e o kernel permitia certas operações de root mesmo dentro do namespace. O workaround foi configurar user_namespace.max_user_namespaces=0 no host, mas isso quebra containers normais. Uma alternativa mais suave é usar mount namespaces com nosuid e noexec, e garantir que nenhum device especial seja passado pro container.

Limitações e quandonão usar

Caixa de areia fechada não protege contra side-channel attacks como cache timing ou rowhammer. Se sua ameaça inclui um atacante que já está dentro do processo ou do host, a sandbox não ajuda. Também não é adequada para executar código potencialmente malicioso com intenção de análise forense — pra isso, VMs com snapshots e rede espelhada são melhores, mesmo que mais pesadas. Outro ponto: sandbox nível 3 e 4 adicionam sobrecarga de manutenção significativa. Cada atualização do kernel pode quebrar seus filtros seccomp ou perfis AppArmor sem aviso. Você precisa testar em cada upgrade. Se você precisa de isolamento forte e não quer gerenciar tudo manualmente, considere k8s com Pod Security Admission ou gVisor. O gVisor em particular implementa uma sandbox com seu próprio kernel userspace e lida com muitas das complexidades que exigem configuração manual aqui. O custo é performance — benchmarks mostram perda de 20 a 40% em comparação com execução direta no kernel, mas para muitos workloads isso é aceitável.

Caixa de areia fechada serve quando você precisa de controle granular sobre o que cada processo pode fazer. Serve quando a sobrecarga de uma VM é proibitiva e a de um container normal não oferece isolamento suficiente. Não serve quando você precisa de proteção contra ameaças internas sofisticadas ou quando não tem recursos pra manter as regras atualizadas.