Segurança
Pedro Kiefer
Posted on November 16, 2021
Segurança é um dos temas mais em voga no momento, especialmente depois dos grandes ataques de ransomware que aconteceram no Brasil e no mundo. Segurança deve permear todos os passos do desenvolvimento de software e não ser uma camada que jogam por cima. Claro, em sistema legados talvez seja a única solução possível e mesmo assim será um cobertor curto — algum pedaço vai ficar desprotegido.
Quando estamos começando um projeto novo, devemos olhar para a segurança desde o princípio. Algumas escolhas simples podem fazer toda a diferença. Isso é parte do príncipio de shift left, isto é, trazer segurança para dentro dos times e deixar de ser uma responsabilidade de um time só de segurança.
Todos são responsáveis pela segurança — incluíndo as pessoas não técnicas, ou talvez especialmente elas. Imaginem se a portaria deixa entrar alguém que não deveria? De nada adianta dez camadas de segurança no software se qualquer um entra no prédio e tem acesso a rede local, ou se deixamos as senhas anotadas na mesa. Temos que balancear o nível paranóia com o bom senso. Nenhum dos extremos funciona bem.
Olhando para o compilado de vulnerabilidades feito pela OWASP temos um ótimo panorama de quais sãos os problemas mais comuns. A maioria é evitável simplesmente se prestarmos atenção e entendermos que vulnerabilidades existem. Por exemplo, ataques de injeção são conhecidos desde 1998 e praticamente todas as bibliotecas para acesso de banco de dados possuem funções que evitam esse tipo de ataque. Basta uma simples escolha para resolver uma classe inteira de problemas. Outros são um pouco mais complexos, mas nada de outro planeta. Com a ajuda de uma equipe de segurança qualquer time está apto a sanar todos.
Existem diversas ferramentas que prometem milagres, fazem análise de código, análise em tempo de execução, filtram requisições maliciosas, etc., mas o mais importante é ter uma cultura que entenda que segurança vem primeiro e faz parte da qualidade do software entregue. As ferramentas podem auxiliar, indicando onde devemos olhar, mas são só ferramentas. Um time com conhecimento vai sempre se sair melhor que ferramentas — especialmente se as ferramentas não forem totalmente compreendidas pelo time. Criar uma cultura é bem mais demorado, envolve treinamentos e participação de todos, mas os benefícios são incrivelmente maiores.
Código e Linguagens
Quando olhamos para segurança sob a ótica do código precisamos ter em mente que aquele software deve atender algum usuário. Se criarmos algo super seguro, mas de difícil uso, poucas pessoas irão usar ou encontrarão formas de burlar a burocracia da segurança — especialmente se forem desenvolvedores. Então é necessário encontrar um meio termo entre segurança e uso. Aceitar que o risco sempre existirá, mas estamos minimizando ele ao máximo. Todo o software é inseguro por natureza. O único software totalmente seguro é aquele que ainda não foi escrito — depois de escrito ele será inseguro, ou rodará num ambiente inseguro. Encontre o balanço de segurança / utilidade ideal para o contexto do negócio.
Nunca é demais repetir, mas valide todas as entradas — inclusive aqueles headers HTTP que parecem inofensivos.
Não deixe chaves de acesso, senhas, ou qualquer dado sensível no meio do código fonte ou configuração. Gerencie as senhas com um sistema próprio para isso. Tenha cuidado redobrado se o projeto for público, uma senha vazada pode ser a porta de entrada para diversos tipos de ataques.
As linguagens de programação evoluíram muito nos últimos 20 anos e surgiram algumas linguagens com modelos de memória mais seguros — Rust
sendo o melhor exemplo. Escolher uma linguagem com um modelo de memória seguro dá diversos benefícios e barra muitos tipos de ataques. Um modelo de memória seguro é tão importante que diversos projetos opensource estão reescrevendo partes em Rust para justamente não terem mais problemas com o comportamento indefinido do C
— a biblioteca de criptografia do python, ou mais recentemente o próprio kernel do linux. Go
adicionou suporte nativo a fuzzing para justamente facilitar testes e aumentar a segurança das aplicações que adotam essa prática — fuzzing consiste em testar diversos tipos de dados para uma entrada qualquer, se o teste falha temos uma potencial falha de segurança ou somente um bug.
Criptografia
Use e abuse de soluções de criptografia, mas não tente inventar a sua. Todos os algoritmos envolvidos na geração de chaves criptográficas fortes são difícies de implementar. Um pequeno erro pode fazer que um gerador de números aleatórios vire uma máquina de repetição, um atacante facilmente criaria uma chave igual. Existem ótimas bibliotecas prontas e seguras para criptografia.
Use criptografia no trânsito de dados, mesmo que seja entre sistemas internos — a maioria dos protocolos já possuem uma versão com TLS. Garanta que os dados estejam cifrados quando em repouso, todos os sistemas operacionais e banco de dados como serviço suportam.
Infraestrutura
Uma das camadas fundamentais para um sistema seguro é a infraestrutura onde rodamos nossos sistemas. Se utilizamos um provedor de nuvem, eles garantem a segurança física dos servidores, mas cabe a nós garantir que o sistema está seguro. Assuma sempre que o ambiente está comprometido — mesmo não estando —, defina o mínimo de privilégios necessários para cada parte da infraestrutura. Não é simples aplicar esse tipo de pensamento em um ambiente já existente, então começe pequeno, garanta que novos sistemas já surjam com os acessos mínimos. Aqui estamos aplicando os princípios de Zero Trust.
Para quem trabalha mais com frontend, ou mobile, troquem nuvem por navegador ou dispositivo móvel. Os mesmos conceitos se aplicam e alguns casos de uso podem inclusive fazer parte das ferramentas de desenvolvimento.
Posted on November 16, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
July 29, 2024