Desenvolvimento

17 mar, 2014

Segurança no Agile: histórias de segurança, de usuários malvados e de abusos

Publicidade

Porque as equipes de desenvolvimento ágil trabalham a partir do backlog de histórias, uma maneira de injetar segurança no desenvolvimento de aplicativos é escrevendo histórias de riscos de segurança e de aplicações e atividades como histórias, tornando-as explícitas e colocando-as no backlog para que o trabalho de segurança do aplicativo possa ser gerenciado, estimado, priorizado e feito como tudo o mais que a equipe tem que fazer.

Histórias de segurança

SAFECode tentou fazer isso escrevendo um conjunto comum de histórias de segurança não-uncionais seguindo o template bem-conhecido

Como um [tipo de usuário] Eu quero{algo} para {razão}

Essas histórias não são para o cliente ou com foco no usuário: não são do tipo que o dono do produto entenderia ou com que se preocuparia. Em vez disso, eles são feitos para a equipe de desenvolvimento (arquitetos, desenvolvedores e testadores). Exemplo:

Como um arquiteto/desenvolvedor, quero garantir E, como CONTROLE DE QUALIDADE, eu quero verificar que dados sensíveis serão mantidos restritos aos atores autorizados a acessá-los.

Há histórias para evitar/verificar vulnerabilidades de segurança comuns em aplicações: XSS, path tranversal, execução remota, CSRF, injeção de comandos do sistema operacional, injeção de SQL, ataque de força bruta. Checagens para exposição de informações por meio de mensagens de erro, uso adequado de criptografia, autenticação e gerenciamento de sessão, segurança da camada de transporte, restrição de uploads e de redirecionamento a URL de sites não confiáveis e questões básicas de qualidade de código: checagem por ponteiros NULL, checagem de limites, de conversão numérica, de inicialização, sincronização de threads/processos, tratamento de exceções, uso de funções restritas/inseguras.

O SAFECode também inclui uma lista de práticas seguras de desenvolvimento (tarefas operacionais) para a equipe, o que inclui garantir que você está usando o compilador mais recente, aplicar os patches nas bibliotecas e run-times, análise estática, busca de vulnerabilidades, revisões de código de alto risco, controle e correção de bugs de segurança e práticas mais avançadas que necessitam de ajuda de especialistas em segurança, como fuzzing, modelagem de ameaças, testes de invasão, e hardening do ambiente.

No geral, essa é uma boa lista de problemas que precisam ser vigiados e de coisas que devem ser feitas na maioria dos projetos. Mas, embora as histórias do SAFECode sejam parecidas com outras histórias, elas não podem ser usadas como histórias comuns pela equipe.

Essas histórias de segurança são requisitos não-funcionais (NFRs, na sigla em inglês) e restrições técnicas que (como requisitos para escalabilidade e facilidade de manutenção e suporte) precisam ser considerados no projeto do sistema e podem precisar ser incluídos como parte da definição de feitos e condições de aceitação para cada história de usuário em que a equipe trabalha.

Histórias de segurança não podem ser retiradas da carteira e entregues como outras histórias e retiradas do backlog quando elas são concluídas, porque nunca são “concluídas”. A equipe tem que se manter preocupada com elas durante toda a vida do projeto e do sistema.

Como Rohit Sethi aponta, pedir aos desenvolvedores malabarismos com longas listas de restrições técnicas como essa, não algo é prático:

Se você começar a acrescentar outras restrições NFR, tais como acessibilidade, a lista de restrições pode crescer rapidamente esmagadoramente para os desenvolvedores. Uma vez que a lista cresce de forma incômoda, a nossa experiência é que os desenvolvedores tendem a ignorar a lista inteiramente. Eles, em vez disso, confiam em suas próprias memórias para aplicar restrições NFR. Como o número de NFRs continua a crescer em domínios cada vez mais especializados, como segurança de aplicativos, a carga cognitiva sobre memórias dos desenvolvedores é substancial.

OWASP, Histórias de usuários malvados – Hackeando o backlog

Alguém na OWASP sugeriu uma alternativa, um conjunto muito menor de histórias de usuários não-funcionais que podem ser “hackeados” para dentro do backlog:

  • Um caminho para um profissional de segurança inserir o tema segurança em algum lugar na agenda da equipe de desenvolvimento é “hackeando o backlog”. A forma de fazer isso é através da elaboração de histórias de usuários malvados, alguns casos negativos em geral que a equipe precise considerar quando for implementar outras histórias.
  • Exemplo # 1. “Como um hacker, posso enviar dados ruins em URLs para que eu possa acessar os dados e funções para as quais eu não estou autorizado.”
  • Exemplo # 2. “Como um hacker, posso enviar dados ruins no conteúdo dos pedidos, para que eu possa acessar os dados e funções para as quais eu não estou autorizado.”
  • Exemplo # 3. “Como um hacker, posso enviar dados ruins nos cabeçalhos HTTP, para que eu possa acessar os dados e funções para as quais eu não estou autorizado.”
  • Exemplo # 4. “Como um hacker, posso ler e até modificar todos os dados que são a entrada e a saída de sua aplicação.”

Pensando como um cara malvado – casos e histórias de abusos

Outra forma de reforçar a segurança no desenvolvimento de software é fazer com que a equipe de desenvolvimento observe atentamente o sistema que eles estão construindo a partir da perspectiva do cara malvado.

Em “casos de utilização indevida e abusiva: ultrapassando o que é positivo”, o Dr. Gary McGraw, no Cigital, fala sobre a importância de antecipar as coisas que vão mal e pensar sobre os comportamentos que o sistema precisa impedir. Suponha que o cliente/usuário não vai se comportar bem, ou seja, que vai atacar o sistema ativamente. Questione todos os pressupostos do projeto (os “pode, não pode”), especialmente as condições de confiança – e se o cara malvado estiver em qualquer lugar ao longo do caminho de uma ação (por exemplo, usando um proxy de ataque entre o cliente e o servidor)?

Casos de abuso são criados por especialistas em segurança trabalhando com a equipe, como parte de uma revisão crítica – tanto para o projeto, quanto para um aplicativo existente. O objetivo de uma revisão como essa é entender como o sistema se comporta em condições ataque/falha e documentar quaisquer deficiências ou lacunas que precisam ser abordadas.

No Agile 2013, Judy Neher apresentou um workshop prático sobre como escrever histórias de agressores, um resumo de uma prática Agile que faz com que “pensar como um cara malvado” seja parte do trabalho da equipe em definir e refinar os requisitos dos usuários.

Tome uma história e, como parte da elaboração da história e da listagem os cenários, dê um passo atrás e olhe para a história através da lente da segurança. Não basta pensar no que o usuário quer fazer e pode fazer – pense no que eles não querem fazer e no que não podem fazer. Peça para que as mesmas pessoas que estão trabalhando na história “coloquem seus chapéus pretos (de crackers)” e faça um brainstorm para chegar aos casos negativos.

Como {um cara malvado} quero {fazer uma coisa ruim}…

O {cara malvado} não tem que ser um hacker. Eles pode ser um funcionário rancoroso ou um cliente egoísta que está disposto a tirar proveito de outros usuários, ou um administrador que precisa ser protegido de cometer erros custosos, ou um sistema externo que nem sempre pode funcionar corretamente.

Faça perguntas como: como faço para saber quem é o usuário e que posso confiar nele? Quem tem permissão para fazer o que e onde as verificações de autorização são aplicadas? Procure por lacunas nos fluxos de trabalho de várias etapas: o que acontece se alguém ignorar uma checagem ou tentar pular uma etapa ou fazer algo fora de sequência? O que acontece se uma ação ou checagem der timeout, bloquear ou falhar – que acessos devem ser permitidos, que tipo de informação deve ser mostrada, que tipo não deve? Estamos interagindo com crianças? Estamos lidando com o dinheiro? Com funções controles e comandos perigosos de administração? Com dados confidenciais ou privados?

Olhe os dados mais de perto. De onde é que eles estão vindo? Posso confiar neles? A fonte é autenticada? Onde ela é validada – tenho que verificar eu mesmo? Onde os dados são armazenados (eles precisam ser armazenados)? Se precisam ser armazenados, deve ser criptografados ou mascarados (incluindo arquivos de log)? Quem deve ser capaz de vê-los? Quem não deve ser capaz de vê-los? Quem pode mudá-los, e as mudanças precisam ser auditadas? Será que preciso ter certeza de que os dados não foram adulterados (checksum, HMAC, assinatura digital)?

Use esse exercício para chegar a critérios de refutação (usuário pode fazer isso, mas não posso fazer aquilo, pois eles podem ver isso, mas não podem ver aquele outro), em vez disso, ou como parte das condições de aceitação para a história. Priorize esses casos com base no risco, adicione os casos que você concorda que precisam ser cuidados nos cenários das histórias atuais, ou como novas histórias para o backlog, caso sejam grandes o bastante.

“Pensar como um cara malvado” ao trabalhar em uma história parece mais útil e prático do que outras abordagens baseadas em histórias.

Isso não leva muito tempo e não é caro. Você não precisa escrever histórias de agressores para cada história de usuário, e quanto mais histórias de agressores você fizer, mais fácil vai ficar – você vai ficar melhor nisso continuará encontrando os mesmos tipos de problemas que podem ser resolvidos com os mesmos modelos.

Você acaba com algo concreto, funcional e utilizável, trabalho que pode ser feito e testado. Casos concretos e usáveis como esses são mais fáceis para a equipe entender e apreciar – incluindo o dono do produto, o que é crítico no Scrum, pois o dono do produto decide o que é importante e o que é feito. E porque histórias de agressores são feitas em fases, pelas pessoas que já estão trabalhando nas histórias (em vez de uma atividade separada que precisa ser configurada e agendada), elas são mais propensas a serem feitas.

Modelagens de ameaças simples, rápidas e informais como essas não são suficientes para fazer um sistema seguro – a equipe não será capaz de encontrar e conectar todos as falhas de segurança dessa forma, mesmo que os desenvolvedores sejam bem treinados em desenvolvimento de software seguro e levem seu trabalho a sério. Histórias de agressores são boas para identificar vulnerabilidades na lógica de negócios, revisando recursos de segurança (autenticação, controle de acesso, auditoria, gerenciamento de senhas, licenciamento), melhorando o tratamento de erros e a validação básica, e mantendo as normas de privacidade em jogo.

Segurança de software eficaz envolve muito mais trabalho do que isto: a escolha de um bom framework e usá-lo corretamente, prestando atenção às mudanças na superfície de ataque do sistema, revisando cuidadosamente o código de alto risco do projeto e erros de programação, escrevendo bom código de defesa tanto quanto possível por meio de análise estática para pegar erros comuns de programação, e testes de segurança regulares (testes de invasão e análise dinâmica). Mas conseguir que os desenvolvedores e os testadores pensem como um cara malvado quando eles construírem um sistema já é um longo avanço para melhorar a segurança e a robustez do seu aplicativo.

***

Artigo traduzido pela Redação iMasters, com autorização do autor. Publicado originalmente em http://swreflections.blogspot.com.br/2013/10/adding-appsec-to-agile-security-stories.html