Aplicações Node.js normalmente herdam as permissões do usuário que iniciou o processo. Isso significa que o código pode ler arquivos, abrir conexões, criar processos filhos e acessar recursos disponíveis ao sistema operacional. O Permission Model no Node.js adiciona uma camada de restrição dentro do runtime para reduzir o que a aplicação pode fazer.
O modelo não substitui usuários sem privilégio, containers, políticas do sistema operacional ou controles de rede. Ele funciona como defesa adicional: mesmo que uma dependência tente acessar um diretório não autorizado ou iniciar um processo, o runtime pode bloquear a operação.
Neste guia, você aprenderá a ativar o modelo, liberar leitura e escrita de caminhos específicos, controlar processos filhos e Worker Threads, consultar permissões em tempo de execução, planejar a migração e entender os limites de segurança.
O que é o Permission Model?
O Permission Model é um mecanismo do Node.js que restringe capacidades do processo. A documentação oficial de permissões do Node.js descreve as flags e APIs disponíveis. O guia oficial de boas práticas de segurança complementa a defesa em profundidade.
Para entender o processo hospedeiro, consulte Objeto Process no Node.js. O guia de File System no Node.js explica operações de leitura e escrita que podem ser restringidas.
Ativando permissões
node --permission server.jsAo ativar o modo, capacidades sensíveis ficam bloqueadas por padrão e precisam ser liberadas explicitamente. O comportamento exato e as flags disponíveis dependem da versão do Node.js.
Liberando leitura de arquivos
node \
--permission \
--allow-fs-read=/srv/app/config \
server.jsO processo pode ler o caminho permitido, mas outras regiões continuam bloqueadas. Use caminhos absolutos e diretórios mínimos.
Liberando vários caminhos
node \
--permission \
--allow-fs-read=/srv/app/config \
--allow-fs-read=/srv/app/public \
server.jsRepita a opção conforme a sintaxe suportada pela versão. Não libere a raiz inteira apenas para resolver um erro inicial.
Escrita em diretório específico
node \
--permission \
--allow-fs-read=/srv/app \
--allow-fs-write=/srv/app/uploads \
server.jsSeparar leitura e escrita reduz o impacto de uma vulnerabilidade. Arquivos de configuração podem ser somente leitura, enquanto uploads ficam em diretório dedicado.
Caminhos relativos
Evite permissões relativas porque o diretório de trabalho pode variar:
--allow-fs-read=./configPrefira caminhos absolutos resolvidos pela implantação. Veja Módulo Path no Node.js para normalização e contenção.
Globs e padrões
Algumas versões oferecem padrões para caminhos. Teste cuidadosamente porque um padrão amplo pode permitir mais conteúdo do que o esperado. Documente a expansão real no ambiente de produção.
Processos filhos
Por padrão, o Permission Model pode bloquear criação de processos filhos. Quando necessário, use a opção correspondente da versão:
node \
--permission \
--allow-child-process \
script.jsEssa permissão é ampla. Um processo filho herda capacidades do sistema operacional e pode executar comandos externos. Prefira remover a dependência quando possível.
O artigo de Child Process no Node.js explica validação de argumentos e riscos de shell injection.
Worker Threads
node \
--permission \
--allow-worker \
server.jsA flag libera criação de Worker Threads quando suportada. Workers compartilham o processo e podem acessar recursos conforme o modelo aplicado.
Veja Worker Threads no Node.js para pools e isolamento de tarefas de CPU.
Consultando uma permissão
const canReadConfig = process.permission.has(
'fs.read',
'/srv/app/config/settings.json'
);A API permite adaptar comportamento antes de tentar uma operação. O nome das permissões e a assinatura dependem da versão.
Fallback controlado
if (process.permission?.has('fs.write', cacheDirectory)) {
await writeCache();
} else {
logger.info('disk_cache_disabled');
}Não desative o modelo automaticamente quando uma permissão falta. Ajuste a arquitetura ou a configuração de implantação.
Permissão não é autenticação
O modelo controla capacidades do processo, não usuários da aplicação. Ele não substitui autenticação, autorização por rota, validação de dados ou regras de negócio.
Permissão não é sandbox completa
Executar código não confiável continua perigoso. O runtime possui APIs, addons nativos e comportamentos que precisam ser considerados. Use processos isolados, containers, usuários restritos e limites de recursos para código hostil.
Defesa em profundidade
Combine o modelo com:
- usuário sem privilégio;
- filesystem somente leitura;
- volumes específicos;
- políticas de rede;
- seccomp ou mecanismos equivalentes;
- limites de CPU e memória;
- gestão de segredos;
- atualização de dependências.
Containers
Em um container, monte apenas os diretórios necessários e ative permissões dentro do Node.js. Se o processo escapar de uma regra do runtime, ainda encontra limites do container.
docker run \
--read-only \
--tmpfs /tmp \
-v uploads:/srv/app/uploads \
appO exemplo é apenas parte da política. Ajuste usuários, capabilities e rede.
Aplicação web típica
Uma API pode precisar:
- ler arquivos estáticos;
- ler certificados;
- gravar uploads;
- gravar logs, se não usar stdout;
- acessar arquivos temporários;
- criar workers para tarefas pesadas.
Liste cada necessidade e libere somente os caminhos correspondentes.
Configuração e segredos
Se a aplicação usa variáveis de ambiente, talvez não precise ler arquivos de segredo. Evite montar diretórios inteiros com credenciais.
O guia de Variáveis de Ambiente no Node.js apresenta validação e proteção de configurações.
Uploads
Conceda escrita apenas ao diretório de uploads e gere nomes controlados:
const destination = path.join(
uploadRoot,
`${crypto.randomUUID()}.bin`
);O Permission Model não valida extensão, conteúdo ou tamanho. Essas regras continuam na aplicação.
Arquivos temporários
Bibliotecas podem usar /tmp ou diretório equivalente. Durante a migração, identifique essas dependências e conceda um diretório temporário específico.
Evite liberar todo o filesystem porque uma biblioteca não documenta seu comportamento.
Logs
Em containers, prefira stdout e stderr. Isso elimina necessidade de escrita em diretórios de log e simplifica coleta.
Veja Console no Node.js para logs estruturados e backpressure.
Bibliotecas legadas
Uma dependência pode ler:
- diretório atual;
- home do usuário;
- arquivos de configuração globais;
- certificados do sistema;
- cache de pacotes;
- binários externos.
Execute testes com o modelo ativo para descobrir acessos ocultos. Substitua dependências que exigem permissões excessivas sem motivo.
Migração gradual
- ative em desenvolvimento;
- execute testes unitários;
- execute testes de integração;
- registre acessos bloqueados;
- corrija caminhos;
- reduza permissões;
- valide em homologação;
- libere gradualmente em produção.
Não comece com permissões globais e adie a redução indefinidamente.
Testes automatizados
Inclua comandos de teste que iniciam o processo com as mesmas flags de produção:
node \
--permission \
--allow-fs-read=/workspace/fixtures \
--testAlgumas ferramentas de teste criam workers, arquivos temporários ou cobertura. Ajuste permissões para o ambiente de testes sem copiar cegamente para produção.
Testando negações
test('bloqueia leitura fora da raiz', async () => {
await assert.rejects(
fs.readFile('/etc/passwd'),
error => error.code === 'ERR_ACCESS_DENIED'
);
});O código do erro pode variar. Consulte a versão e use asserts compatíveis.
Observabilidade
Registre falhas de permissão com:
- operação;
- caminho sanitizado;
- versão da aplicação;
- instância;
- contexto da operação.
Não registre conteúdo de arquivos ou segredos.
Incidentes
Se uma permissão bloqueia uma função legítima em produção, não reinicie com acesso total como primeira reação. Identifique a capacidade mínima e altere a implantação de forma auditada.
Dependências comprometidas
O modelo pode reduzir o impacto de uma dependência maliciosa que tenta ler chaves SSH ou iniciar comandos. Ele não impede roubo de dados que a aplicação já tem permissão para acessar.
Por isso, minimize também os dados disponíveis ao próprio processo.
Performance
Checagens de permissão adicionam algum custo. Faça benchmark em caminhos críticos, mas não desative segurança por diferenças pequenas sem medir impacto real.
Compatibilidade de versão
O Permission Model evoluiu ao longo das versões do Node.js. Fixe uma versão LTS suportada, consulte as flags correspondentes e teste antes de atualizar.
Erros comuns
- Liberar a raiz: o modelo perde utilidade.
- Usar caminhos relativos: comportamento muda conforme cwd.
- Confiar como sandbox: faltam controles externos.
- Ignorar bibliotecas: dependências acessam caminhos ocultos.
- Liberar child process sem necessidade: comandos externos ficam disponíveis.
- Copiar flags de desenvolvimento: produção recebe permissões excessivas.
- Não testar negações: regras podem parecer ativas sem bloquear o esperado.
Boas práticas
- Use permissões mínimas.
- Prefira caminhos absolutos.
- Separe leitura e escrita.
- Evite child process.
- Combine com usuário sem privilégio.
- Use filesystem somente leitura.
- Teste em CI.
- Fixe a versão do runtime.
- Monitore acessos negados.
- Revise permissões a cada nova dependência.
Conclusão
O Permission Model no Node.js reduz capacidades do processo e ajuda a limitar leitura, escrita, processos filhos e workers. Ele é especialmente útil para conter erros e dependências que tentam acessar recursos desnecessários.
A segurança real vem da combinação de camadas. Permissões do runtime, usuário restrito, container, filesystem mínimo, rede controlada e validação da aplicação trabalham juntos. Ao mapear necessidades e liberar somente o essencial, a equipe reduz a superfície de ataque sem impedir a operação legítima do serviço.




