Como posso criar e acessar com segurança arquivos temporários a partir de shell scripts?
14
Li que redirecionar a saída para um arquivo de nome fixo /tmppode ser um risco à segurança, porque se um invasor (ou descontente) perceber que um arquivo /tmp/tmpfileformyscript.tmpé criado quando executo meu script (mesmo que ele não tenha acesso de leitura ao meu script), ele pode, por exemplo, criar um link simbólico ln -s ~wildcard/.bashrc /tmp/tmpfileformyscript.tmpque fará com que eu destrua meu .bashrcarquivo quando executo o script.
Então, em vez disso, posso usar algo como filename="tmpfile.tmp.$RANDOM" ; echo outputtext > "$filename".
No entanto, às vezes, eu gostaria de usar um arquivo tmp para armazenar em cache; nesse caso, eu gostaria de saber se "tmpfile.tmp. *" Corresponde a algo /tmpe, nesse caso, use esse arquivo em vez de criar um novo. Infelizmente, testo equivalente [ -f filename ]não suporta globbing de arquivos, até onde eu sei.
Assim, minha pergunta é dupla:
Como posso criar com segurança um arquivo temporário? É "predictablename.$RANDOM"uma prática aceitável ou existe uma maneira melhor (mais segura, mais fácil)?
Como posso acessar facilmente o arquivo e / ou estabelecer sua existência posteriormente, verificando predictablename?
Use o mktemputilitário para criar um arquivo temporário com um nome imprevisível. Não é padronizado pelo POSIX, mas está disponível no * BSD e no Linux.
> /tmp/predictable.$RANDOMnão é uma boa escolha, pois é previsível¹, o que abre o script para um ataque em que o invasor pode induzi-lo a substituir um arquivo ao qual você tem acesso de gravação ou a fornecer acesso temporário ao arquivo. Esta é uma vulnerabilidade insegura de arquivos temporários . mktempnão possui essa vulnerabilidade porque cria o arquivo com segurança (não substitui um arquivo existente, mesmo se houver links simbólicos) e usa um nome suficientemente imprevisível para evitar uma negação de serviço.
Se criar um arquivo temporário e trabalhar com ele não for bom o suficiente, crie um diretório temporário mktemp -de trabalhe nele.
mktemptambém toma cuidado $TMPDIRse a variável estiver definida, retornando para /tmpse estiver desabilitada.
Cada vez mais distribuições são configuradas TMPDIRpara serem um diretório privado, por exemplo, /run/1234/tmponde 1234está o seu UID. Isso elimina o risco de vulnerabilidades temporárias de arquivos, ao custo de não ser mais possível compartilhar arquivos temporários entre usuários (o que é ocasionalmente útil, mas não com muita frequência; /tmpainda está disponível, apenas não TMPDIR).
Se você precisar de um nome de arquivo reproduzível, crie um arquivo com um nome bem definido (sem componente aleatório) no diretório inicial do usuário. A convenção moderna é a especificação do diretório de usuários XDG . Se o arquivo puder ser removido sem causar perda de dados, use a XDG_CACHE_HOMEvariável de ambiente, padrão como ~/.cache. Você provavelmente deve criar um subdiretório nomeado após o seu aplicativo e trabalhar nele.
¹ Não apenas $RANDOMleva 32767 valores possíveis, mas é fácil prever sem tentar muitos valores. O gerador de números aleatórios do Bash é um LCG semeado pelo PID e pela hora do primeiro uso. O Zsh é a plataforma randsemeada pelo tempo de inicialização. O ATT Ksh's é randsemeado pela plataforma PID. O Mksh's é um LCG com uma semente mais complexa, mas ainda sem qualidade de segurança. Todos eles podem ser previstos por outro processo com uma chance bastante grande de sucesso.
Na verdade, sua discussão $TMPDIRe ~/.cacheé exatamente o que eu precisava. Após algumas reflexões, percebi que a única razão pela qual eu queria /tmpera particionar - para que o cache não pudesse preencher a /homepartição. Mas, para este caso de uso, isso é realmente um não problema, portanto, um subdiretório ~/.cachese ajusta perfeitamente às minhas necessidades e evita o problema de segurança.
Curinga
mktempnão está disponível no AIX ou no shell Git no Windows. Parece que file.$RANDOM$RANDOMé a solução portátil. O $RANDOM$RANDOMespaço deve aumentar para 2 ^ 32, assumindo que os resultados aleatórios do Bash sejam independentes e não fracos.
Os resultados aleatórios do @jww Bash são fracos: é um LCG, que é quase tão previsível quanto possível, sendo bom o suficiente para muitos aplicativos que não exigem imprevisibilidade.
Gilles 'SO- stop be evil'
9
O mktemp foi projetado para isso. Na página do manual:
O mktemp criará o arquivo ou sairá com um status de saída diferente de zero. O lógico ou (||) garante que o script será encerrado se o mktemp não conseguir criar o arquivo. Após esse comando, você pode ter certeza de que o arquivo está disponível. Não há necessidade de verificar novamente. A única coisa que você pode precisar adicionar é a limpeza do arquivo no final do seu script.
E possivelmente também quando o script é finalizado por um sinal. Se isso é necessário ou não, é algo que você precisa decidir.
Ah! Isso é muito útil; então eu não preciso ligar $RANDOM. Mas, então, a parte 2 da minha pergunta - como posso acessar esse arquivo posteriormente ou verificar se ele já existe em uma execução subsequente do script? (Para implementar um cache muito simples).
$TMPDIR
e~/.cache
é exatamente o que eu precisava. Após algumas reflexões, percebi que a única razão pela qual eu queria/tmp
era particionar - para que o cache não pudesse preencher a/home
partição. Mas, para este caso de uso, isso é realmente um não problema, portanto, um subdiretório~/.cache
se ajusta perfeitamente às minhas necessidades e evita o problema de segurança.mktemp
não está disponível no AIX ou no shell Git no Windows. Parece quefile.$RANDOM$RANDOM
é a solução portátil. O$RANDOM$RANDOM
espaço deve aumentar para 2 ^ 32, assumindo que os resultados aleatórios do Bash sejam independentes e não fracos.O mktemp foi projetado para isso. Na página do manual:
O mktemp criará o arquivo ou sairá com um status de saída diferente de zero. O lógico ou (||) garante que o script será encerrado se o mktemp não conseguir criar o arquivo. Após esse comando, você pode ter certeza de que o arquivo está disponível. Não há necessidade de verificar novamente. A única coisa que você pode precisar adicionar é a limpeza do arquivo no final do seu script.
E possivelmente também quando o script é finalizado por um sinal. Se isso é necessário ou não, é algo que você precisa decidir.
Ambos podem ser feitos usando o
trap
comandofonte
$RANDOM
. Mas, então, a parte 2 da minha pergunta - como posso acessar esse arquivo posteriormente ou verificar se ele já existe em uma execução subsequente do script? (Para implementar um cache muito simples).