Boas práticas de segurança para desenvolvedores web
A segurança web não é opcional. Diante do aumento constante das ameaças cibernéticas, os desenvolvedores devem incorporar a segurança em cada camada de suas aplicações. Este guia cobre as práticas essenciais que você deveria implementar hoje mesmo.
Segurança de Senhas
Nunca armazene senhas em texto puro
Sempre aplique hash nas senhas usando algoritmos modernos como bcrypt, Argon2 ou scrypt. Esses algoritmos são projetados para serem lentos, o que torna os ataques de força bruta impraticáveis.
// Correto: Usando bcrypt
const bcrypt = require('bcrypt');
const hash = await bcrypt.hash(password, 12);
Comparação de algoritmos de hashing
Nem todos os algoritmos de hashing são iguais. A escolha do mais adequado depende do seu modelo de ameaças e caso de uso:
| Algoritmo | Tamanho da saída | Velocidade | Caso de uso | Status de segurança |
|---|---|---|---|---|
| MD5 | 128 bits | Muito rápido | Checksums, hashes não relacionados à segurança | Quebrado para segurança |
| SHA-256 | 256 bits | Rápido | Integridade de dados, assinaturas digitais | Seguro |
| bcrypt | 184 bits | Lento (configurável) | Hashing de senhas | Seguro |
| Argon2 | Configurável | Lento (configurável) | Hashing de senhas (moderno) | Recomendado para projetos novos |
bcrypt e Argon2 são deliberadamente lentos — isso é uma funcionalidade, não um defeito. Cada operação de hash leva dezenas ou centenas de milissegundos, o que torna os ataques de força bruta em larga escala economicamente inviáveis.
Entendendo a entropia das senhas
A força de uma senha pode ser medida matematicamente usando a entropia: entropia = log2(tamanho_charset^comprimento). Uma senha que usa apenas letras minúsculas (26 caracteres) com 8 caracteres tem ~37,6 bits de entropia. Uma senha de 16 caracteres que combina maiúsculas, minúsculas, dígitos e símbolos (95 caracteres) tem ~105 bits — exponencialmente mais difícil de quebrar. Por isso o comprimento importa mais que a complexidade para a maioria dos usuários. Para uma exploração mais profunda da matemática por trás da força das senhas, consulte nosso guia de entropia de senhas explicada.
Use um gerenciador de senhas
Recomende aos seus usuários que adotem um gerenciador de senhas. As senhas escolhidas por humanos tendem a seguir padrões previsíveis que os atacantes exploram com ataques de dicionário. Os gerenciadores de senhas geram cadeias verdadeiramente aleatórias e eliminam a reutilização de senhas entre serviços — um dos vetores mais comuns de ataques de credential stuffing.
Use rodadas de salt suficientes
As rodadas de salt determinam o custo computacional. Mais rodadas significam mais segurança, mas também mais lentidão. De 10 a 12 rodadas é um bom equilíbrio para a maioria das aplicações.
Validação de entradas
Valide tanto no cliente quanto no servidor
A validação do lado do cliente melhora a experiência do usuário, mas a validação do lado do servidor é essencial para a segurança. Nunca confie nas entradas do cliente.
Sanitize todas as entradas de usuário
Previna ataques de injeção sanitizando as entradas:
- Use consultas parametrizadas para SQL
- Escape a saída HTML para prevenir XSS
- Valide rigorosamente os uploads de arquivos
Exemplos concretos de ataques
Entender os ataques reais ajuda você a se defender deles. Considere um formulário de comentários que renderiza diretamente em HTML a entrada do usuário. Um atacante envia:
<script>alert('xss')</script>
Se a aplicação renderiza isso sem escapar, o script é executado no navegador de todos os visitantes — roubando cookies, redirecionando usuários ou injetando keyloggers. A solução: sempre codifique a saída de forma contextual. Use bibliotecas como DOMPurify para a sanitização de HTML.
A injeção SQL é igualmente perigosa. Em um formulário de login, um atacante insere como nome de usuário:
' OR 1=1 --
Se a consulta é construída com concatenação de strings ("SELECT * FROM users WHERE username='" + input + "'") isso ignora a autenticação completamente. O -- comenta o restante da consulta. A solução: sempre use consultas parametrizadas (também chamadas de prepared statements). Todas as grandes bibliotecas de banco de dados as suportam:
// ERRADO: Concatenação de strings
db.query(`SELECT * FROM users WHERE username='${input}'`);
// CORRETO: Consulta parametrizada
db.query('SELECT * FROM users WHERE username = $1', [input]);
Política de segurança de conteúdo (CSP)
Como defesa em profundidade, implemente cabeçalhos de Política de Segurança de Conteúdo. A CSP indica ao navegador quais fontes de conteúdo são confiáveis, bloqueando efetivamente os scripts inline e o carregamento de recursos não autorizados. Mesmo que exista uma vulnerabilidade XSS no seu código, uma CSP rigorosa pode impedir que o script injetado seja executado. Comece com Content-Security-Policy: default-src 'self' e adicione exceções gradualmente conforme necessário.
Funções Hash
Escolher o hash correto
Os diferentes casos de uso requerem diferentes funções hash:
| Caso de uso | Recomendado |
|---|---|
| Senhas | bcrypt, Argon2 |
| Integridade | SHA-256 |
| Checksums | SHA-256, MD5 (não relacionado à segurança) |
| Hashing rápido | BLAKE3 |
Entendendo a saída hash e as colisões
O MD5 produz um hash de 128 bits (32 caracteres hexadecimais), enquanto o SHA-256 produz um de 256 bits (64 caracteres hexadecimais). Essa diferença importa: um espaço de saída maior implica exponencialmente mais valores hash possíveis, o que torna as colisões muito menos prováveis. Uma colisão ocorre quando duas entradas diferentes produzem o mesmo hash — um atacante que possa fabricar colisões pode falsificar assinaturas digitais ou manipular dados verificados.
As colisões de MD5 podem ser geradas em segundos em hardware moderno. O SHA-256 continua sendo resistente a colisões sem ataques práticos conhecidos. Por isso escolher o algoritmo correto para o contexto adequado é importante:
- Checksums e deduplicação: MD5 é aceitável quando a segurança não é uma preocupação
- Integridade de dados e assinaturas: SHA-256 fornece uma forte resistência a colisões
- Armazenamento de senhas: bcrypt ou Argon2, que adicionam salt e desaceleração deliberada
HMAC para a autenticação de mensagens
Quando você precisa verificar tanto a integridade quanto a autenticidade de uma mensagem, use HMAC (Hash-based Message Authentication Code). O HMAC combina uma função hash com uma chave secreta, o que garante que apenas as partes que conhecem a chave possam gerar ou verificar a tag. Isso é essencial para a autenticação de APIs, a verificação de webhooks e a geração de tokens seguros.
Nunca use MD5 ou SHA-1 para segurança
MD5 e SHA-1 estão quebrados para propósitos de segurança. Use SHA-256 ou SHA-3 para o hashing criptográfico.
HTTPS em todo momento
O que o TLS realmente faz
O TLS (Transport Layer Security) fornece três proteções: criptografia em trânsito (evitando escutas), autenticação do servidor (provando que você está falando com o servidor real e não com um impostor) e integridade dos dados (detectando qualquer manipulação durante a transmissão). Sem TLS, cada dado entre seus usuários e seu servidor — senhas, tokens, informações pessoais — viaja em texto puro.
Use sempre TLS
- Obtenha certificados de CAs confiáveis (Let’s Encrypt é gratuito e completamente automatizado)
- Redirecione HTTP para HTTPS
- Use cabeçalhos HSTS
- Mantenha atualizadas as versões de TLS
HSTS e conteúdo misto
Os cabeçalhos HTTP Strict Transport Security (HSTS) indicam aos navegadores que se conectem apenas por HTTPS, mesmo se o usuário digitar http://. Configure Strict-Transport-Security: max-age=31536000; includeSubDomains para forçar isso durante um ano completo em todos os subdomínios. Isso previne os ataques de SSL stripping onde um atacante rebaixa uma conexão para HTTP.
Cuidado com os avisos de conteúdo misto: se sua página HTTPS carrega imagens, scripts ou folhas de estilo por HTTP, os navegadores os bloquearão ou emitirão avisos. Verifique suas páginas em busca de URLs http:// codificadas e utilize caminhos relativos ao protocolo ou force HTTPS para todos os recursos.
Autenticação
Implemente limitação de taxa
Previna os ataques de força bruta com limitação de taxa:
- Limite as tentativas de login por IP
- Adicione atrasos após tentativas falhas
- Use CAPTCHA para atividade suspeita
Conceitos básicos de autenticação JWT
Os JSON Web Tokens (JWT) fornecem um mecanismo de autenticação stateless estruturado como cabeçalho.payload.assinatura. O servidor assina o token com uma chave secreta, e os clientes o incluem nas requisições posteriores. Como o token contém as claims do usuário, o servidor não precisa consultar o estado de sessão em cada requisição — o que torna os JWTs ideais para sistemas distribuídos e microsserviços.
Sempre defina tempos de expiração curtos nos tokens de acesso (por exemplo, 15 minutos) e use refresh tokens para obter novos tokens de acesso. Armazene os refresh tokens de forma segura (cookies httpOnly, não localStorage) e implemente a rotação de tokens para que cada refresh token só possa ser usado uma vez.
Autenticação multifator (MFA)
A MFA não é mais opcional para nenhuma aplicação séria. Exigir um segundo fator — códigos TOTP (Google Authenticator), chaves hardware (YubiKey) ou notificações push — reduz drasticamente o impacto das senhas comprometidas. Mesmo que um atacante obtenha credenciais válidas, não consegue se autenticar sem o segundo fator.
Prevenção da fixação de sessão
Os ataques de fixação de sessão ocorrem quando um atacante estabelece um ID de sessão conhecido antes que o usuário se autentique. Após o login, o atacante usa esse mesmo ID de sessão para sequestrar a sessão autenticada. Previna isso sempre regenerando o ID de sessão após uma autenticação bem-sucedida e invalidando o anterior.
Use um gerenciamento seguro de sessões
- Gere IDs de sessão com aleatoriedade criptográfica
- Defina as flags secure e httpOnly nos cookies
- Implemente timeout de sessão
- Invalide as sessões ao fazer logout
Lista de verificação de cabeçalhos de segurança
Implementar os cabeçalhos de resposta HTTP corretos é uma das formas mais efetivas e de baixo esforço para reforçar sua aplicação. Aqui está uma tabela de referência rápida com os cabeçalhos de segurança essenciais:
| Cabeçalho | Propósito | Valor de exemplo |
|---|---|---|
| Content-Security-Policy | Prevenir XSS e injeção de dados | default-src 'self' |
| Strict-Transport-Security | Forçar conexões HTTPS | max-age=31536000; includeSubDomains |
| X-Content-Type-Options | Prevenir o sniffing de tipos MIME | nosniff |
| X-Frame-Options | Prevenir clickjacking | DENY |
| Referrer-Policy | Controlar a informação do referrer | strict-origin-when-cross-origin |
Esses cabeçalhos podem ser configurados no nível do servidor web (Nginx, Apache), no nível de CDN/edge (Cloudflare, Vercel) ou dentro do seu framework de aplicação. Teste seus cabeçalhos com ferramentas como securityheaders.com. Mire em uma pontuação A+ — a maioria desses cabeçalhos é uma única linha de configuração e não custa nada para implementar.
Usando nossas ferramentas de segurança
Explore nossas ferramentas de segurança para ajudar no seu desenvolvimento:
- Gerador de Hash MD5 - Para checksums e sistemas legados
- Gerador de UUID - Para identificadores aleatórios seguros
- Gerador de Senhas Aleatórias - Para gerar senhas robustas
Para uma visão mais ampla de como as ferramentas de codificação, hashing e conversão se encaixam no seu fluxo de desenvolvimento, consulte nossa Guia essencial de ferramentas para desenvolvedores.
Perguntas frequentes
Qual é a vulnerabilidade de segurança web mais comum?
O Cross-Site Scripting (XSS) continua sendo a vulnerabilidade web mais prevalente segundo a OWASP. Ocorre quando as aplicações incluem dados não confiáveis em páginas web sem a validação adequada. Previna o XSS sanitizando todas as entradas de usuário, usando cabeçalhos de Política de Segurança de Conteúdo e codificando a saída segundo o contexto (HTML, JavaScript, URL ou CSS).
O MD5 ainda é seguro para o hashing de senhas?
Não — o MD5 nunca deveria ser usado para o hashing de senhas. É computacionalmente rápido, o que o torna vulnerável a ataques de força bruta e de tabelas arco-íris. As GPUs modernas podem calcular bilhões de hashes MD5 por segundo. Use bcrypt, scrypt ou Argon2, que são deliberadamente lentos e incluem salt incorporado para resistir a ataques.
Quantos caracteres uma senha segura deve ter em 2026?
Recomenda-se um mínimo de 12 caracteres, mas 16 ou mais proporcionam uma proteção significativamente maior. O comprimento importa mais que a complexidade — uma frase de 20 caracteres como “cavalo-correto-bateria-grampo” é mais forte que uma senha curta e complexa como “P@ss1!”. Ative a autenticação multifator (MFA) independentemente do comprimento da senha para as contas críticas.
Qual é a diferença entre criptografia e hashing?
A criptografia é reversível — você pode descriptografar os dados de volta à sua forma original usando uma chave. O hashing é unidirecional — não é possível recuperar os dados originais a partir de um hash. Use criptografia para dados que você precisa recuperar (como dados de usuário armazenados) e hashing para dados que você só precisa verificar (como senhas e checksums).
Devo implementar meu próprio sistema de autenticação?
Não — construir a autenticação do zero é arriscado e propenso a erros. Use frameworks e serviços testados em batalha como Auth0, Firebase Auth ou Supabase Auth. Eles gerenciam o hashing de senhas, o gerenciamento de sessões, a rotação de tokens, a MFA e a proteção contra força bruta. Concentre seu tempo de desenvolvimento nas funcionalidades únicas da sua aplicação.
Conclusão
A segurança é um processo contínuo, não uma tarefa pontual. Mantenha-se atualizado sobre as últimas vulnerabilidades, audite seu código regularmente e siga o princípio de mínimo privilégio. Seus usuários confiam seus dados a você — honre essa confiança com práticas de segurança sólidas.