Por Augusto Alves
Prólogo
Bem vindos de volta. Dando sequência ao aprendizado sobre desenvolvimento seguro, na semana passada falamos de um método de prevenção de ameaças (STRIDE) que pode ser usado enquanto programamos as interações que o software faz.
Antes de seguir, gostaria de apresentar exemplos de contramedidas para cada uma das categorias.
Spoofing
Fingir ser alguém que não é.
- Usar um forte sistema de autenticação.
- Não armazenar segredos como senhas em texto puro.
- Não transferir credenciais em texto puro na comunicação.
- Proteger cookies de autenticação com Secure Sockets Layer (SSL).
Tampering
Modificar dados armazenados ou em trânsito.
- Usar comparação de hashes e assinaturas digitais para os dados.
- Usar um forte sistema de autorização.
- Use protocolos que dificultem adulteração nos links de comunicação.
- Usar protocolos de comunicação que permitem checagem de integridade.
Repudiation
Negar que você fez ou não fez algo.
- Logs logs e mais logs (cuidado com armazenamento de dados sensíveis em logs).
- Usar assinatura digital.
Information disclosure
Ver uma informação sem autorização.
- Usar métodos fortes de autorização.
- Usar uma encriptação segura.
- Usar protocolos que garantam confidencialidade
- Não armazenar segredos em texto puro.
- Cuidado com exibição de informação sensível em logs e mensagens de erro.
Denial of service
Tornar um sistema indisponível.
- Usar técnicas de limitação para banda e para recursos do sistema.
- Validar e filtrar entrada de dados e de comunicação.
- Load balancing
Elevation of privilege
Fazer algo sem permissão.
- Use um princípio de minimização de privilégios utilize usuários menos privilegiados para rodar serviços e processos.
Agora seguindo o conteúdo da semana passada falaremos sobre:
Gerenciamento de Sessão
Por natureza o HTTP(s) é um protocolo sem estado, o que quer dizer que cada requisição é independente da outra. Isso faria com que um usuário teria que digitar sua senha a cada clique, sendo dessa forma inoperante.
Para amarrar várias requisições, foram inventadas as sessões HTTP. No começo de cada sessão é gerado um identificador de sessão que é então enviado a cada requisição e é usado para acessar dados do lado do servidor durante a sessão. No final de uma sessão esses dados podem ser limpos da memória e o identificador de sessão não apontará mais para esses dados.
Para usar sessões juntamente com autenticação, alguns detalhes precisam ser observados.
Depois de efetuado o Login, a sessão é criada e é gerado o identificador de sessão. Esse identificador deve ser difícil de prever, já que se for conhecido ele daria à um atacante o poder de acessar dados de algum usuário. Vale mencionar que se esse identificador for transferido por um canal de comunicação não criptografado, um atacante poderia capturar esse tráfego e interceptar o identificador (com softwares como wireshark, burpsuite, zaproxy, etc). Essa encriptação é necessária não só para proteger a senha, mas sim a sessão como um todo.
Ao terminar a sessão, o identificador deve ser invalidado e se um usuário esquecer de efetuar LogOut essa sessão deve ser terminada depois de um período de inatividade.
Como o identificador de sessão deve ser mantido como segredo, não é uma boa prática usar o mesmo identificador já utilizado para uma outra sessão.
Pelo mesmo motivo, o identificador de sessão não deve ser utilizado como parâmetros nas requisições HTTP. Utilizar cookies nesses casos é mais apropriado para gerenciar sessões, já que são enviados a cada requisição e podem ser revogados.
Cross Site Request Forgery (CSRF ou XSRF)
Essa prática acontece quando um atacante faz referência em um site ao conteúdo de outro site e fazer com que o navegador acesse esse conteúdo sem o explícito consentimento do usuário. Por exemplo, um atacante poderia colocar a seguinte “imagem” em seu site:
<img src="”https://eleicoes.com/vote.cgi?candidato=tiririca”">
Quando alguma pessoa acessar o site, o navegador vai automaticamente fazer uma requisição para esse endereço e gerar um voto para o Tiririca. Como o servidor web não pode diferenciar qual requisição foi gerada pelo usuário ele não consegue rejeitar essa requisiçã
A chave para mitigar esse ataque é fazer essa requisição o mais imprevisível possível. Por exemplo:
A aplicação armazenar um valor aleatório nos dados de sessão, esse valor é chamado de CSRF-Token.
Esse token deve ser incluído a cada requisição.
Quando a requisição for feita, a aplicação irá primeiramente verificar se o token da requisição equivale ao token da sessão antes de executar a requisição.
Obviamente esse token deve ser mantido em segredo. Em requisições GET isso pode ser um problema, mas como esse token tem uma validade, esse risco pode ser aceito. O ideal é que cada formulário tenha seu próprio token, mas isso pode gerar problemas na usabilidade quando um usuário abrir múltiplas abas no navegador ou voltar à página anterior. Na prática, esses tokens são únicos por cada sessão de login.
Clickjacking – Roubo de Cliques
Graças ao CSS e JavaScript hoje é possível ter uma interface com diversos elementos numa página da web, é possível até empilhar elementos no topo das outras camadas. Clickjacking abusa dessa técnica para realizar um ataque na camada de interface com o usuário.
Um ataque básico de clickjacking ocorre da seguinte forma. Um atacante anexa o site alvo com um frame que sobrepõe a tela que é exibida. Com CSS, ele define a opacidade para 0% o que deixa o frame completamente transparente. Uma pessoa que visita o site irá carregar tanto a página web atacada quanto o frame adicionado pelo atacante, mas somente virá o site por trás. Os cliques serão capturados pela camada do topo (feita pelo atacante). Dessa forma o atacante consegue convencer a pessoa a realizar cliques numa página invisível e então deixar que a pessoa execute operações normalmente em uma determinada página.
Esses ataques básicos podem ser prevenidos. Navegadores mais atuais tem suporte para um header http chamado de X-Frame-Options, definindo o header para o valor SAME-ORIGIN ou DENY um navegador irá recusar que uma página seja adicionada como frame em outro site. Alguns navegadores utilizam também javascript para determinar se um conteúdo está sendo carregado dentro de um frame. Esse código é chamado de frame-busting code. Entretanto sua eficácia é limitada.