Introdução à Cibersegurança
A maioria dos bugs de segurança em aplicações web são erros de programação comuns com uma consequência incomum.
Uma query é montada colando strings umas nas outras. Um template escreve o nome de um visitante diretamente na página. Uma rota lê um id da URL e retorna o registro sem verificar quem fez o pedido.
Cada um desses casos parece razoável durante a revisão, até o momento em que você vê a requisição que se aproveita dele.
Trabalhar com segurança é, na maior parte do tempo, o hábito de se perguntar o que uma versão hostil desse input faria.
Cada um desses bugs se encontra em uma fronteira de confiança, que é a ideia mais útil deste manual.
O que é uma fronteira de confiança?
Uma fronteira de confiança é a linha entre uma parte do seu sistema que você controla e uma parte que você não controla: o navegador, uma API de terceiros, um arquivo enviado por upload. Tudo que atravessa essa linha precisa ser verificado do outro lado.
Como pensar sobre segurança mostra onde traçar essas linhas em uma aplicação web típica.
O que este manual cobre
Isto é segurança de aplicações para desenvolvedores: a segurança do código que você escreve, revisa e coloca em produção.
Não cobre segurança de redes, análise de malware, monitoramento de blue team, operações de red team ou frameworks de conformidade. Esses são campos extensos, com literatura própria, e quem procura por eles vai ser mais bem atendido em outro lugar.
Todos os exemplos de código são em Node e Express, com Zod para descrever o formato dos dados que você espera, de modo que os exemplos se pareçam com um serviço que você já poderia estar mantendo.
Os capítulos seguem em quatro partes, pensadas para serem lidas em ordem na primeira leitura, porque as últimas se apoiam no vocabulário que a primeira estabelece.
| Parte | O que cobre | Comece em |
|---|---|---|
| 1 · Pensando como um atacante | Identificar por onde dados externos entram, STRIDE para prever ameaças, OWASP para nomear as que já foram encontradas, e como redigir um relatório de bug | Como pensar sobre segurança |
| 2 · Segurança de entrada e dados | Os ataques famosos, que acabam sendo o mesmo erro com fantasias diferentes, e depois a validação que os fecha de uma só vez | Nunca confie no input do usuário |
| 3 · Autenticação e identidade | O HTTP esquece você entre requisições, então todo app escolhe uma forma de lembrar. Três formas, comparadas | Autenticação vs autorização |
| 4 · Limitação e controle de taxa | Manter o serviço respondendo quando o tráfego não coopera. Cinco algoritmos e duas respostas | Fundamentos de rate limiting |
Quatro partes, começando em como pensar e terminando em manter um serviço de pé. Eu ainda volto para a primeira parte mais do que para qualquer outra.
O que você precisa saber antes
Você vai aproveitar mais este material se souber escrever um pouco de JavaScript e já tiver visto um pequeno servidor Node e Express. O suficiente para reconhecer uma rota e uma função de middleware quando aparecerem.
Uma ideia faz mais trabalho aqui do que qualquer outra. Quando alguém visita seu site, o navegador dela envia uma requisição: o endereço que ela pediu, alguns cabeçalhos e, muitas vezes, um corpo carregando o que quer que ela tenha digitado.
Cada uma dessas partes foi escrita por essa pessoa, incluindo as que sua própria página preencheu.
Nada impede alguém de ignorar sua página e enviar o que bem entender.
Um detalhe do Express merece destaque logo de início, já que a maioria das correções depende dele. O middleware roda na ordem em que você o registra, então uma verificação precisa vir antes da rota que confia no resultado dela. Uma registrada depois não protege nada.
O manual de JavaScript cobre o lado da linguagem, e o capítulo sobre o DOM prepara o terreno para os capítulos daqui que tratam de escapar o que você escreve em uma página.
Levei um tempo para parar de tratar meu próprio front-end como uma fonte confiável, e quase tudo aqui fica mais fácil assim que você faz o mesmo. Também não se assume nenhum conhecimento prévio de segurança.
Como ensinamos vulnerabilidades
Todo capítulo que cobre uma fraqueza real segue os mesmos quatro passos, então, depois de ler um, você já sabe se orientar em todos os outros.
- O código com falha, curto o bastante para ler de uma vez e parecido com algo que você encontraria em um projeto real.
- O payload, o input ou requisição real que quebra o código.
- Por que funciona, rastreado pelo código, porque uma correção que você não consegue explicar é uma correção que vai acabar desfazendo mais tarde.
- A correção, com uma nota sobre as variantes que ela cobre e as que não cobre.
No tamanho que uma introdução comporta, os quatro passos ficam assim:
// Vulnerável: o nome é colado diretamente no texto da query
app.get('/users', (req, res) => {
const rows = db.query(`SELECT * FROM users WHERE name = '${req.query.name}'`)
res.json(rows)
})
// Payload: /users?name=' OR 1=1 --
// A aspa fecha a string antes da hora, então OR 1=1 entra na query como uma
// condição própria e casa com todas as linhas da tabela.
// Corrigido: o valor viaja ao lado da query e nunca é interpretado como SQL
const rows = db.query('SELECT * FROM users WHERE name = ?', [req.query.name])Mostrar o payload é proposital. Injeção descrita de forma abstrata passa despercebida, e o mesmo bug é difícil de notar às três da tarde no pull request de outra pessoa.
Uma fronteira vale para tudo
Esses payloads estão aqui para você conseguir encontrar essa classe de bug no código pelo qual você é responsável. Rode-os contra sistemas que você possui ou para os quais tem permissão explícita de teste, e em nenhum outro lugar.
O manual também respeita esse limite: nada de ferramentas de varredura, nada de alvos de terceiros, nada de evasão de detecção, e nenhum passo a passo de como encadear uma fraqueza em outra.
A regra para levar com você é rodar essas coisas apenas nos seus próprios projetos.
Conheça seus guias
Três guias conduzem este manual, e você escolhe qual deles vai te acompanhar.
Todo mundo lê a mesma base, escrita de forma simples para quem está encontrando segurança pela primeira vez. Escolher um guia mais aprofundado adiciona material por cima: o padrão mais amplo, os casos que a primeira correção deixa passar, as escolhas de compromisso por trás dela. Seu guia também define o tom.
Troque de guia a qualquer momento pelo seletor no topo de qualquer página, ou abra Preferências no canto inferior direito para mudar o guia ou o tamanho da fonte.
O nível é a profundidade que você quer no momento, então mude sempre que um capítulo parecer raso ou denso demais. Subir de nível no meio do caminho adiciona o material extra no lugar, mantendo o que você já leu como estava.
Se um capítulo parecer pesado, tente descer de nível só naquela página. Nada se perde, e a base é a mesma por baixo.
Para onde isso vai a seguir
Quatro partes, trinta e dois capítulos, um exemplo funcional quebrado e consertado ao longo de todo o manual.
O que é cibersegurança? delimita a palavra antes de qualquer vocabulário chegar, e então como pensar sobre segurança inicia o hábito sobre o qual o resto do manual funciona.
Prefere aprender construindo?O curso Learn Cybersecurity da Scrimba cobre o mesmo conteúdo por meio de desafios interativos que você resolve no navegador.
