Artigo - Hábitos seguros no desenvolvimento de software

Transcrição

Artigo - Hábitos seguros no desenvolvimento de software
CENTRO UNIVERSITÁRIO DE BRASÍLIA - UniCEUB
Faculdade de Ciências Exatas e Tecnologia - FAET
Curso de Bacharelado em Ciência da Computação
Disciplina: Segurança e Auditoria de Sistemas
Professor: Maurício Rocha Lyra
HÁBITOS SEGUROS:
8 REGRAS SIMPLES PARA O DESENVOLVIMENTO DE
CÓDIGO MAIS SEGURO
Michael Howard
Eu tive muita sorte em trabalhar com milhares de bons
desenvolvedores durante muitos anos, que queriam
aprender a escrever software mais seguros. Durante esse
tempo, também aprendi muito com pessoas que são
muito boas na criação de sistemas seguros e isso me fez
pensar. Imaginei se haveria habilidades ou hábitos
comuns que os "desenvolvedores de segurança"
compartilhavam. E acontece que a resposta foi um
ressonante sim! Este artigo apresenta a lista de hábitos
compartilhados pelos desenvolvedores de código
seguro.
Agora, uma coisa de que tenho certeza é que qualquer
pessoa que for revisar a lista imediatamente notará a
ausência de alguns hábitos. Não há problema. Eu sei
que existem outras ótimas idéias por aí. Esta é minha
lista! Então, dito isso, seguem meus exemplos de
hábitos que observei ao longo dos anos.
Hábito nº 1: Assumir responsabilidade
Essa é uma variação do comentário clássico "There is
no silver bullet" (Não existe uma solução mágica) feito
há mais de 25 anos por Fred Brookes em The Mythical
Man Month. Obter a segurança correta em seu produto
depende totalmente de você. Ninguém mais, e
certamente nenhuma ferramenta mágica ou linguagem
de programação, resolve todos os problemas de
segurança. Não me entenda mal. Eu gosto de
ferramentas de análise de código-fonte, mas elas não
consertarão todas as vulnerabilidades de segurança
como em um passe de mágica. Só você pode fazer isso.
Os produtos seguros são criados pelos desenvolvedores
que criam designs seguros e escrevem códigos seguros.
Finalmente, escrever códigos é um esforço individual.
Você é um indivíduo e não pode ser substituído por
uma ferramenta. Portanto, a segurança de seu produto é
nossa responsabilidade! Os worms Blaster e CodeRed
exploram códigos que foram escritos por indivíduos
(veja a Figura 1).
Figura 1 Código vulnerável escrito por indivíduos
Lembre-se de que todos os códigos serão escrutinados e
possivelmente atacados. Isso é absolutamente normal.
Ser atacado faz parte. A grande questão é: seu código
estará comprometido? Só você pode determinar esse
resultado. Por isso, fique orgulhoso de seu código. Você
deve ficar satisfeito com a qualidade de seu código e
conseguir dormir à noite sabendo que se ele for atacado,
você fez tudo o que era possível para evitar que ele
fosse derrotado.
Se for possível, peça que um colega especialista em
segurança revise seu código. Não deixe que alguém que
não conheça nada sobre segurança examine seu código
e espere que essa pessoa encontre bugs de segurança e
vulnerabilidades. Vá atrás de alguém que realmente
entenda do assunto para analisar seu código.
E, não seja tão prepotente, de modo a não pedir ajuda
quando precisa dela. Eu mencionei que você não deve
confiar exclusivamente nas ferramentas, mas deve, sem
dúvida, aproveitar alguma que esteja disponível.
Execute todas as ferramentas de análise de código-fonte
em seu código e as execute com freqüência. Aproveite
todas as elaborações de linguagem defensiva e truques
de biblioteca possíveis disponíveis. Por exemplo, no
C#, envolva o código referente à rede que executa
acesso a matrizes, em que o índice da matriz é derivado
de uma solicitação de rede, em operadores de
verificação para detectar possíveis erros aritméticos em
inteiros.
Hábito nº 2: Nunca confiar nos dados
Eu já disse isso bilhões de vezes e vou dizer novamente:
toda entrada é “do mal” até que se prove o contrário. Se
você olhar as vulnerabilidades de segurança mais
odiosas, todas compartilham a característica comum de
o desenvolvedor ter confiado nos dados de entrada. O
problema é que se o código assumir que os dados são
bem formados, o que acontecerá se suas suposições
forem incorretas? Em um dia bom, seu aplicativo
provavelmente será interrompido. Em um dia ruim, o
invasor poderia injetar código malicioso em seu
processo e destruí-lo.
A definição quase excêntrica de um sistema seguro é
aquele que executa as tarefas que devem ser executadas
e nada mais. Mas, quando há questões de confiança de
entrada, você geralmente pode conseguir com que o
sistema execute outras tarefas. Uma análise superficial
dos dados de CVE (vulnerabilidades e exposições
comuns) (cve.mitre.org) mostra que de 2001 a 2004, 47
por cento de todas as vulnerabilidades de segurança
rastreadas pela CVE eram questões de confiança de
CENTRO UNIVERSITÁRIO DE BRASÍLIA - UniCEUB
Faculdade de Ciências Exatas e Tecnologia - FAET
Curso de Bacharelado em Ciência da Computação
Disciplina: Segurança e Auditoria de Sistemas
Professor: Maurício Rocha Lyra
entrada. As questões mais conhecidas são saturações de
buffer, bugs aritméticos com inteiros, scripts entre sites
e bugs de injeção de SQL. Estamos começando a ver
novas variações sobre este tema, como vulnerabilidades
de injeção de Xpath e de injeção de protocolo LDAP.
Você pode remediar as questões de confiança de
entrada seguindo algumas regras simples. Primeiro, não
procure apenas coisas que você sabe que são ruins; isso
supõe que você conheça todas as coisas ruins e preveja
todas elas no futuro. Procurar coisas ruins não tem
problema, desde que essa não seja sua única defesa.
Uma estratégia melhor é restringir a entrada daquilo que
você sabe que é bom. Para linguagens de alto nível
como o C# e Perl, gosto de usar expressões regulares
para conseguir isso.
Em seguida, rejeite aquilo que você sabe que é ruim.
Por exemplo, se alguém solicitar remotamente um
arquivo através de seu código e o nome do arquivo
incluir um caractere especial (do tipo : ou \), recuse a
solicitação. E não diga ao invasor o porquê; diga apenas
"arquivo não encontrado."
Finalmente, e isso não funciona em todos os cenários,
desinfete os dados. Por exemplo, no caso de um
servidor da Web, você deveria codificar com HTML a
saída que venha de uma entrada potencialmente não
confiável.
Hábito nº 3: Modelar as ameaças contra seu código
Você tem modelos de ameaças, certo? Os modelos de
ameaça permitem que você entenda os riscos potenciais
para seu software e que se certifique de que tenha as
atenuações apropriadas no lugar. Mas, os benefícios da
modelagem de ameaças se estendem além do design
seguro. Os modelos de ameaças também podem ajudar
na qualidade do seu código. Os modelos de ameaças
informam a você a origem dos dados. Os dados são
remotos ou locais? Os dados são de usuários anônimos
ou de usuários mais confiáveis (autenticados), talvez
administradores?
Com essas informações à mão, você pode determinar se
suas defesas são apropriadas. Por exemplo, o código
acessível a usuários anônimos e remotos deve ser muito
seguro. Não estou dizendo que o código acessível
apenas ao administrador local não deva ser seguro,
estou dizendo que o código acessível remotamente,
especialmente sendo executado por padrão, tem de ser
"à prova de balas", e isso significa mais defesas, mais
revisão e mais atenção a detalhes. Mais que isso, o
modelo de ameaça pode informar a natureza dos dados
que estão sendo protegidos. Dados comerciais de alto
nível e informações identificáveis pessoalmente, por
exemplo, devem ser muito bem protegidas. Suas
defesas são apropriadas?
Certifique-se de que seus modelos de ameaça sejam
precisos e atualizados, depois identifique todos os
pontos de entrada em seu código e classifique-os pela
acessibilidade – remota versus local e usuários muito
privilegiados versus pouco privilegiados (ou sem
privilégios). O código mais acessível deve ser revisto o
mais detalhadamente e o mais cedo possível.
Finalmente, reveja todos os códigos dos caminhos de
dados anônimos; em outras palavras, comece em cada
ponto de entrada acessível anonimamente e trace os
dados pelo caminho, verificando se os códigos estão
corretos.
Hábito nº 4: Ficar um passo à frente
A
paisagem
de
segurança
se
desenvolve
constantemente. Parece que a cada semana há novas
variações de questões de segurança. Isso significa que
você deve se desenvolver e aprender novas ameaças e
defesas ou sofrerá as conseqüências.
Algumas estratégias simples para estar um passo à
frente da curva inclui ler alguns bons livros sobre o
assunto de segurança de software de vez em quando.
Além disso, aprenda com seus erros antigos e, ainda
melhor, com os erros dos outros. Você pode fazer isso
lendo a bugtraq — vá até securityfocus.com e se
inscreva para receber informações da bugtraq em sua
caixa de entrada. Mas, confie em mim neste próximo
conselho: crie uma regra de caixa de entrada para
mover as correspondências para uma pasta especial,
para poder manipular o volume. É significativo.
Hábito nº 5: Difundir!
A difusão é uma técnica de teste inventada para
encontrar bugs de confiabilidade. Descobriu-se que um
percentual
de
bugs
de
confiabilidade
são
vulnerabilidades de segurança esperando pela
exploração certa! Claro, uma saturação do buffer pode
interromper um aplicativo, mas, dada uma transferência
maliciosa bem feita, a interrupção pode não acontecer e
o invasor poderia executar o código para fazer sua
aposta. Nosso lema por aqui é "negar trabalho hoje é
executar código amanhã."
Quase toda a vulnerabilidade/bug para análise de
arquivos foi encontrada por sorte ou difusão. A
Microsoft encontrou vulnerabilidades de segurança
analisando vários formatos de arquivos incluindo
arquivos XLS, PPT, DOC e BMP. Muitos fornecedores
tinham tido vulnerabilidades semelhantes, pois a análise
de estruturas de dados complexas é uma tarefa difícil. O
código complexo tem bugs, e alguns desses bugs
revelarão vulnerabilidades de segurança.
Você precisa difundir todos os códigos que analisam
arquivos e tráfego de rede. O SDL (ciclo de vida do
desenvolvimento da segurança) da Microsoft é muito
específico no que se refere ao significado disso para os
formatos de arquivo. Você precisa difundir todas as
análises com 100 mil iterações de arquivos
malformados usando um difusor de arquivo. Existem
vários difusores razoáveis disponíveis e nós incluímos
um difusor de arquivo, bem como código-fonte C++, no
livro The Security Development Lifecycle, (em inglês)
do qual fui co-autor junto com Steve Lipner
(microsoft.com/MSPress/books/8753.asp).
Uma última observação sobre difusão. Se ocorrer uma
interrupção, não pense que é simplesmente uma
CENTRO UNIVERSITÁRIO DE BRASÍLIA - UniCEUB
Faculdade de Ciências Exatas e Tecnologia - FAET
Curso de Bacharelado em Ciência da Computação
Disciplina: Segurança e Auditoria de Sistemas
Professor: Maurício Rocha Lyra
interrupção. É provável que um grande percentual das
supostas interrupções esteja implorando para que
alguém escreva uma exploração. Portanto, não
considere uma interrupção como "apenas uma
interrupção."
Hábito nº 6: Não escrever código inseguro
Na Microsoft, utilizamos o conceito de Quality Gates
(sistema de garantia de qualidade) para ajudar na
redução das chances de o desenvolvedor verificar
código vulnerável no produto. Os gates (portões)
executam uma bateria de ferramentas de análise de
código-fonte no código antes do check-in sinalizar
algum problema. E quaisquer problemas identificados
devem ser resolvidos antes do check-in ser concluído.
Você também pode forçar regras estritas de código,
como excluir o uso de funcionalidades banidas, como
nenhuma chamada para strcpy nem strncat e nenhuma
criptografia pobre. (A Microsoft baniu mais de 100
funções de tempo de execução C para código novo!).
Por exemplo, em relação à criptografia, não permitimos
DES (o tamanho da chave é muito pequeno), MD4, nem
MD5 (estão ambos quebrados agora) em código novo, a
menos que um padrão da indústria exija seu uso.
Não reinvente funcionalidade. Se você tiver um código
que analise um formato de arquivo específico, não
precisa de duas ou três etapas da análise de código.
Fique com aquela definida, torne-a robusta e a envolva
em uma forma que possa ser utilizada em vários
projetos.
Finalmente, lembre-se de que as ferramentas não devem
substituir o conhecimento de como escrever código
seguro. É por isso que o aprendizado de segurança e
privacidade é tão importante. Você precisa ter um
conhecimento sólido dos conceitos para poder discernir
as chamadas e os insights que suas ferramentas são
capazes de fazer.
Hábito nº 7: Reconhecer a assimetria estratégica
Esse é um dos meus favoritos. Lembre-se de que como
desenvolvedor de software, as probabilidades de
segurança estão todas contra você. Gosto de chamar
isso de "vantagem do invasor e dilema do defensor."
Você precisa que o código seja 100% projetado
corretamente, 100% do tempo, e isso é impossível. Para
dificultar ainda mais, você precisa atingir essa meta
insuperável com um orçamento fixo, enquanto tem de
considerar
requisitos
de
suportabilidade,
compatibilidade, acessibilidade e outras "-bilidades".
Um invasor pode gastar todo o tempo que quiser para
encontrar um bug e depois contar ao mundo inteiro que
seu aplicativo é inseguro.
No Hábito nº 6, mencionei que você deveria parar de
escrever código novo inseguro. Para o Hábito nº 7, você
deve se concentrar em todos os códigos, pois os
invasores atacam todos os códigos, independentemente
da idade. Dedique algum tempo revisando código
antigo, procurando vulnerabilidades de segurança, e
considere seriamente a substituição de funcionalidades
antigas e inseguras. Se você utiliza métodos de
desenvolvimento ágeis, deve pensar em dedicar uma ou
mais oportunidades para resolver códigos antigos,
levando a qualidade dos códigos recentes até eles.
Hábito nº 8: Utilizar as melhores ferramentas que
puder
Finalmente, utilize as melhores ferramentas possíveis.
Eu adoro as ferramentas de análise de código-fonte e
adoro qualquer tecnologia que me ajude a escrever
código mais seguro. Conforme mencionei, as
ferramentas não são panacéias, mas ajudam. E muito!
As ferramentas também ajudam a escalar o problema de
análise de código-fonte. As ferramentas conseguem
examinar enormes quantidades de código rapidamente,
com muito mais velocidade do que um humano seria
capaz. E essa ajuda dá a você uma idéia de como alguns
códigos podem ser "maus".
Um dos meus truques favoritos é compilar o código
usando o mais alto nível possível de avisos, como por
exemplo, /W4 quando uso o Visual C++® ou –Wall
quando uso gcc. Se você vir um grande número de
avisos em um código, talvez ele tenha outros bugs que
não foram localizados pelo compilador ou por outras
ferramentas. Esse código deve estar sujeito a um maior
grau de escrutinação antes de sua expedição (veja
Hábito nº 3).
Esses são os oito bons hábitos que percebi utilizados
pelos desenvolvedores que respeito profundamente,
tanto dentro quanto fora da Microsoft. Os hábitos por si
só não o tornarão um desenvolvedor seguro e célebre,
mas com certeza ajudarão!
Michael Howard é gerente de programa de segurança
sênior na Microsoft e se concentra no aprimoramento e
processo seguro e nas práticas recomendadas. Ele é o
co-autor de cinco livros de segurança, incluindo The
Security Development Lifecycle, Writing Secure Code e
19 Deadly Sins of Software Security (em inglês).