Coluna do Kurt
COLUNA
Programação
segura
Nosso especialista de segurança fala sobre os softwares
para auditar e garantir a segurança de seus programas.
U
m dos temas consistentes no livro Coders at
Work, de Peter Seibel, é: Como ser um programador melhor? Essa ideia me é muito interessante porque, no mundo da segurança, percebo as
pessoas cometendo sempre os mesmos erros.
Depois de certo tempo, é de se esperar que as pessoas aprendessem a criar um arquivo temporário com
segurança. Que ao menos aprendessem a criar, acessar
e apagar buffers de memória de forma segura; no entanto, não é o caso de muitos programadores (incluindo
alguns muito bons). Portanto, a resposta é prestar atenção às pessoas que escrevem códigos seguros, copiá-las e
aprender com elas. Mas como fazer isso, principalmente
quando não se tem tempo nem verba?
Muitos programadores gostam de compartilhar, e a
beleza do conhecimento e da informação é que podemos transmitir o que sabemos sem perder nada. Felizmente, alguns programadores se deram ao trabalho de
organizar seu conhecimento e sabedoria em pacotes de
softwares; de fato, o número de bibliotecas disponíveis
hoje é impressionante (graças a essas pessoas, poucos
hoje precisarão escrever um cliente HTTP ou um parser HTML). Portanto, qual o programa necessário para
desenvolver softwares melhores e mais seguros?
Valgrind
O Valgrind é provavelmente a ferramenta de código
aberto (licença GPL) mais madura para análise de
binários e de código-fonte, não apenas com relação à
segurança, mas também ao desempenho (os dois costumam caminhar juntos). Provavelmente o componente
mais eficaz para detectar e solucionar problemas de
segurança é o memcheck.
O módulo memcheck encontra posições de memória
que estejam sendo acessadas incorretamente, valores não
inicializados que estejam sendo usados de modo perigoso,
vazamentos de memória (sempre um potencial problema
16
de negação de serviço) e uma liberação ruim de blocos
do heap (frees duplos ou desencontrados); além disso,
ele pode detectar quando o programa informa blocos de
memória sobrepostos para origem e destino.
Instalação
A instalação é trivial:
yum install valgrind
ou
apt-get install valgrind
A compilação do código-fonte também é fácil:
$
$
$
$
$
#
cd valgrind
./autogen.sh
./configure --prefix=/path
make
su make install
Uso
No uso do Valgrind, as coisas se complicam um pouco. O programa gera uma saída volumosa. Algumas são
falsos positivos (ou fatos não tão perigosos) e separar o
joio do trigo pode ser bem trabalhoso. Isso nos remete
diretamente ao Debian Bug Report Log 363516.
De forma resumida, nesse caso famoso o Valgrind avisava sobre o uso de memória não inicializada e, em vez de
usar um arquivo de supressão (para fazer o Valgrind parar
de reclamar) ou simplesmente examinar atentamente o
código, o desenvolvedor optou simplesmente por comentar
as linhas culpadas. Infelizmente, isso resultou em um pool
de entropia previsível que acabou resultando em chaves
OpenSSL totalmente previsíveis no Debian. Como acontece com várias ferramentas poderosas, se elas forem usadas
http://www.linuxmagazine.com.br
Insegurança | COLUNA
sem a total compreensão, as consequências podem ser negativas. Dois excelentes vídeos no SecurityTube mostram
os princípios do uso do Valgrind no Linux.
Se você, assim como eu, precisa programar, mas não
confia muito nas suas habilidades com relação à segurança e nem conhece muito bem programas como o
Valgrind, o que você pode fazer?
Linguagem mais segura
Há uma solução realmente simples que dá conta da
maioria dos problemas relacionados ao gerenciamento
de memória, tais como alocação correta (uso de memória
não inicializada etc.), uso seguro (estouro e underflow de
buffer etc.) e garantia de que a memória seja destruída
corretamente (free duplo, vazamentos de memória etc.):
use uma linguagem de programação com gerenciamento
de memória embutido (Python, Java, Perl etc.).
Com elas, não é necessário se preocupar com o
comprimento de uma string ou de um vetor ao criá-los.
Simplesmente, crie uma string ou vetor e jogue os dados
neles. O buffer se expande conforme necessário e, ao
lê-lo, não será possível ir além do fim da string, pois o
interpretador do programa simplesmente retornará um
erro informando que não há mais dados ou itens para
leitura (em vez de ler áreas aleatórias da memória). A
desvantagem, logicamente, é que alguns problemas e
programas não se adaptam bem a essas linguagens (quase todas as implementações dessas linguagens são em
C, que é o pesadelo do gerenciamento de memória).
Auditoria de código: PyChecker
Além disso, por ser um fiel usuário do Unix, uso um
programa simples e eficiente para verificação de código Python, o PyChecker. Trata-se de uma ferramenta
para conferir código-fonte em Python. Embora o interpretador Python seja capaz de detectar vários erros de
programação (e então levantar uma exceção, imprimir
um erro e terminar o programa), alguns deslizes acabam escapando. O uso de uma variável global em uma
classe, em vez de uma variável self (que existe somente
naquela instância da classe e é, portanto, muito mais
segura em um ambiente com threads), pode gerar vários tipos de problemas de difícil solução. No entanto,
o PyChecker consegue detectá-los e passar a informação imediatamente.
Instalar o PyChecker é fácil:
$
$
$
$
wget http://download.site/pychecker-0.8.18.tar.gz
tar -xf pychecker-0.8.18.tar.gz
cd pychecker-0.8.18
python setup.py install
Aprenda programação segura
Mesmo com tudo isso, ainda não chegamos à questão
da educação. Para uma programação segura é necessário entender, ou pelo menos conhecer, os vários tipos
de falhas que comprometem essa questão. Desde as
questões mais simples, como os vários tipos de estouros de buffer, até o esotérico “Use of a Non-reentrant
Function in an Unsynchronized Context”.
O projeto Common Weakness Enumeration (CWE
– Enumeração das Falhas Comuns) foi desenvolvido
exatamente para isso. Ele organizou uma lista completa
das falhas de segurança dos softwares, com descrição,
informações sobre as soluções e exemplos das falhas.
Algumas das entradas do CWE possuem exemplos de
códigos e, infelizmente, a maioria das entradas necessita de mais informações sobre a solução ou prevenção
do problema. Mas, como já foi dito por alguém, “Agora
você sabe, e saber já é meio caminho andado”.
O próximo passo, logicamente, é aprender o comportamento e o mecanismo da programação segura. Apesar
das dezenas de livros disponíveis atualmente, alguns muito bons, prefiro os recursos online. Um dos melhores e
mais abrangentes documentos é o Secure Programming
for Linux and Unix HOWTO de David A. Wheeler.
Outro projeto que tenta melhorar a segurança dos
softwares é o Open Web Application Security Project
(OWASP – Projeto Aberto de Segurança de Aplicativos
Web). Apesar de se dedicar a aplicativos web, a maioria
do conteúdo dos guias de desenvolvimento, de revisão
de código e de teste pode ser aplicado a softwares não
baseados na web. O mais importante é que eles incluem
ferramentas de verdade e documentação específica
para a programação segura, além do “WebGoat”, um
aplicativo propositalmente inseguro que ensina através
de erros alheios.
Conclusão
Programação segura não é complicada. Ela basicamente
requer disciplina, o que significa enfrentar as dificuldades,
compreender o que as mudanças no código irão gerar
(principalmente se o código original não for seu). n
$ easy_install PyChecker
Caso isso não funcione, é possível instalá-lo manualmente baixando o tarball do PyChecker, descompactando-o e executando a instalação manualmente:
Linux Magazine #63 | Fevereiro de 2010
Kurt Seifried é consultor de segurança da informação especializado
em redes e Linux desde 1996. Ele frequentemente se pergunta como
a tecnologia funciona em grande escala mas costuma falhar em
pequena escala.
17
Download

Programação segura