Tutorial Linux – Parte 5

Foto de um teclado de computador com retroiluminação branca

Capítulo 5. Assuntos a considerar

5.1. Segurança

O desenvolvimento de shell scripts requer cuidados extremados com segurança. Em qualquer ambiente profissional, segurança é um assunto importante e que deve ser levado em conta. É comum ouvir argumentos como “não precisamos nos preocupar com isso, temos um firewallťť ou coisa parecida, mas esses são os argumentos mais perigosos. Um firewall dá sempre uma falsa sensação de segurança. Um firewall não protege, por exemplo, a rede interna de uma empresa de seus próprios funcionários – a principal origem de ataques contra a estrutura de TI de qualquer empresa. Além disso, mesmo que ataques não ocorram, boa parte dos furos de segurança são bugs que podem causar interrupção de serviço. Manter uma disciplina de escrever scripts seguros, além de ser uma boa política de segurança, é uma boa disciplina que certamente evitará horas de manutenção desnecessária no futuro.

Vamos ver alguns dos problemas mais comuns de segurança com relação a shell scripts.

5.2. Permissões excessivamente permissivas

Ao criar arquivos, verifique se eles realmente devem ser lidos por todo o sistema. Use o umask para setar restrições maiores. Não deixe informação visível a não ser que seja estritamente necessário.

Por outro lado, não tente proteger seu script sendo obscuro e pedante. Boa segurança é aquela que, mesmo exposta para o todo o mundo, ainda é robusta. Não baseie sua estratégia de segurança no desconhecimento da maneira como ela funciona. E mantenha o usuário em perspectiva. Manter arquivos sem permissões de leitura para o sistema todo é uma boa política, mas se isso for necessário para o funcionamento do ambiente de produção, não exite em relaxar a permissão (mas analise as alternativas, como criar grupos de pessoas que podem acessar tais logs).

5.3. Race conditions

Uma maneira muito comum de ataque é se aproveitar da criação de arquivos temporários. Com uma pequena manipulação do ambiente, é possível que um usuário não autorizado crie um link simbólico no lugar de algum arquivo temporário usado por um script (ou por qualquer programa). Como as ações praticadas em um link se refletem no arquivo para o qual ele aponta, é possível sobrescrever e mudar permissões de arquivos importantes do sistema.

A maneira mais simples de evitar isso é não usar um diretório temporário compartilhado como o /tmp. Crie um diretório apenas para o usuário, como $HOME/tmp. Sete as variáveis $TMP e $TMPDIR para esse diretório. Se for necessário usar um diretório compartilhado, use o mktemp, que cria nomes de arquivos não predizíveis de maneira segura. Evite construções que usam $$, já que a variável de ambiente $$ (sinônimo do PID do shell) é facilmente predizível na maioria dos sistemas UNIX.

5.4. Dados importantes aparecendo como parâmetros

Cuidado com o conteúdo de dados importantes. Em primeiro lugar, dados como senhas devem estar protegidos no sistema de arquivos por permissões apropriadas (o ideal seria não armazenar senhas em disco). Ao manipular senhas, lembre-se que elas ficam em memória e podem ser bisbilhotadas por outros programas. Nunca passe senhas por parâmetros – eles aparecem na listagem do ps. Use pipes.

5.5. Verifique o $PATH e o $IFS

As variáveis de ambiente $PATH e $IFS são muito importantes. Modificar seus conteúdos pode quebrar o funcionamento do script de muitas maneiras. Sete manualmente e sempre o valor dessas variáveis no topo do script. Uma pessoa que mude um PATH, por exemplo, pode fazer com que um dado importante (como uma senha, ou dados confidenciais) sejam enviados para os programas errados, possivelmente programas que essa pessoa mesmo manipula. Adicionalmente, nunca ponha o diretório atual (.) no PATH.

5.6. Evite scripts setuid

A melhor recomendação com relação a scripts setuid é “não use”. Há inúmeros problemas que podem ser usados para conseguir acesso ao usuário dono do script. Se necessário, use um wrapper compilado ou utilize o sudo. Cada sistema UNIX requer cuidado específico quanto à segurança de shell scripts setuid. Consulte o manual de seu sistema operacional caso precise utilizar esse recurso. Nem todo sistema UNIX suporta shell scripts setuid, então esse é o tipo de solução não portável.

5.7. Favoreça portabilidade

A plataforma pode mudar de um dia para o outro. De maneira geral, escrever scripts já é uma solução portável, mas requer cuidados para não usar recursos específicos de uma determinada plataforma. Mesmo que a mudança de plataforma não pareça algo que possa acontecer, lembre-se que o problema do ano 2000 também parecia não ser algo que pudesse acontecer.

5.8. scripts frágeis

Scripts frágeis podem, em cascata, quebrar o ambiente de produção. Verifique sempre o código de retorno dos comandos para ter certeza de que eles funcionaram como esperado. Ao fazer comparações usando [, sempre inclua as variáveis sendo comparadas entre aspas. Valide dados. Se não é necessário expandir uma variável dentro de uma string, use aspas simples ao invés de duplas. Espere que a entrada de seus programas seja algo extremamente variável (seja bastante permissivo com o que pode entrar) e gere uma saída rigidamente definida.

5.9. Escreva código reutilizável

Sempre que possível, evite fazer código específico para um problema. Gastar um pouquinho de tempo a mais com código reutilizável pode salvar horas de esforço posterior. Além disso, centralizando as principais funções de seu script em torno de código reutilizado significa que há apenas um lugar para consertar ao invés de dezenas de lugares. É possível evoluir e tornar mais robusta uma função reutilizável e ter impactos positivos em todo o sistema.

Por exemplo, se você está escrevendo uma função que lida com logs, possivelmente vai precisar de fazer um processamento de datas. Essas funções de processamento de datas podem ser utilizadas por analisadores de um tipo de log diferente, ou ainda por programas que não são analisadores de log. Criar uma biblioteca de funções de datas e incluí-las nos demais scripts é bem mais inteligente que reescrever as funções diversas vezes.

5.10. KISS

Keep It Simple, Stupid. Não tente escrever aplicações inteiras com shell scripts. Escreva pequenos scripts que realizam operações específicas e que você pode garantir que funcionam bem (essa é uma forma bastante prática de reutilizar código!) e conecte esses utilitários.

Além disso, dentro de scripts, não use estratégias mirabolantes. Use expressões regulares com cuidado, favoreça legibilidade.

5.11. Comente seus scripts

Escreva comentários. Diga para que servem as funções, mas não explique o óbvio. Comentários devem ser escritos para pessoas que conhecem a linguagem, então não é necessário explicar que FOO=bar seta a variável FOO com valor bar. Se o código é muito longo ou complicado, um comentário explicando o que ele faz (não como ele faz) é bem vindo.

5.12. Marque áreas que devem ser consertadas

Algumas vezes, é necessário usar uma solução frágil para resolver rapidamente um problema. Porém, é necessário marcar essa solução para que depois possa ser revisada com mais calma. Ponha um comentário com o texto FIXME e uma explicação do que deve ser consertado. Alguns editores de texto destacam com cores diferentes o texto FIXME, e usar uma string padronizada torna fácil encontrar os pontos em que o script deve ser consertado.

5.13. Indente o código

“Indentar” o código é fundamental para facilitar a compreensão. Separe os blocos de comandos e indente-os de acordo.

5.14. Use variáveis descritivas (mas não muito)

Variáveis de ambiente devem ter um nome minimamente descritivo de sua função. Uma boa variável para conter um nome, por exemplo, é $nome. Não chame essa variável de $n, que seria uma maneira de tornar o programa mais críptico, mas também não chegue no extremo de chamar de $nomedapessoaretiradodatabelatal. Variáveis com nomes muito descritivos são normalmente muletas para um programa excessivamente complicado.

Continua…