Boas práticas de segurança web: guia camada por camada (2026)
Ponto-chave
As boas práticas de segurança web funcionam em camadas: proteja o domínio e o DNS (registrar lock, DNSSEC, CAA), force TLS moderno com HSTS, envie um conjunto rígido de cabeçalhos de segurança HTTP, faça o hash das senhas com Argon2id, protegido por MFA e rate limits, valide as entradas e imponha o controle de acesso no servidor, fixe e audite as dependências, feche todas as portas que você não usa e registre logs suficientes para perceber uma invasão. Cada prática abaixo vem com a configuração exata e uma forma grátis de verificar se ela está realmente funcionando, porque um controle que você não testou é um controle que você não tem.
Verifique agora

Comece a ler
- O que são boas práticas de segurança web
- A pilha de segurança web: seis camadas para proteger
- Camada 1: blinde o domínio e o DNS
- Camada 2: HTTPS e TLS bem configurados
- Camada 3: cabeçalhos de segurança HTTP
- Camada 4: autenticação que resiste ao credential stuffing
- Sessões, cookies e CSRF
- Injeção e XSS: valide a entrada, codifique a saída
- Broken Access Control: o risco número um
- Camada 5: dependências e a cadeia de suprimentos de software
- Camada 6: hardening do servidor (portas, patches, segredos, backups)
- Autenticação de e-mail: SPF, DKIM e DMARC
- Registre logs, monitore e prepare-se para a invasão
- Teste tudo: scanners, pentests e verificações contínuas
- Checklist de segurança web
- Como isso se relaciona com o OWASP Top 10:2025
- Perguntas Frequentes sobre Boas Práticas de Segurança Web
O que são boas práticas de segurança web
Boas práticas de segurança web são o conjunto de controles que impedem que um site ou uma aplicação web seja invadido, desfigurado, usado para atacar os próprios visitantes ou drenado de dados em silêncio. Não se trata de um único produto nem de uma única configuração. É uma pilha de decisões que começa no registrador do domínio e passa pelo DNS, pelo TLS, pelos cabeçalhos HTTP que o seu servidor envia, pelo código que cuida de logins e entradas de dados, pelos pacotes de terceiros sobre os quais você constrói, pelo próprio servidor e, por fim, pelos logs que avisam quando algo deu errado.
O motivo para pensar em camadas é que os atacantes pensam. O 2026 Data Breach Investigations Report da Verizon, que cobre mais de 22.000 violações de novembro de 2024 a outubro de 2025, constatou que 31% das violações começaram com uma vulnerabilidade de software explorada, contra 20% um ano antes e, pela primeira vez, à frente das credenciais roubadas (13%), com o phishing estável em 16%. O ransomware apareceu em 48% das violações, contra 44%. Basta um único patch faltando, uma chave de API vazada ou uma página de administração sem limite de tentativas. Nenhum dos controles deste guia é exótico; os sites invadidos costumam ser os que ignoraram o básico em uma camada enquanto poliam outra.
Este guia é organizado de fora para dentro. Cada prática diz por que importa, o que configurar exatamente e como verificá-la com um comando ou uma ferramenta gratuita como o Verificador de Cabeçalhos HTTP ou o Verificador de SSL, porque uma configuração que você acredita estar ativa, mas nunca confirmou, não protege nada.
Check a site's security headers
A pilha de segurança web: seis camadas para proteger
Todo ataque a um site atinge uma de seis camadas. A tabela abaixo é o mapa do restante deste guia: o que fica em cada camada, como ela costuma ser atacada e qual verificação grátis confirma que a sua defesa está realmente funcionando.
| Camada | O que os atacantes fazem aqui | Práticas essenciais | Verifique com |
|---|---|---|---|
| 1. Domínio e DNS | Sequestram o domínio, trocam os nameservers, assumem subdomínios órfãos, obtêm certificados fraudulentos | Registrar lock, MFA, DNSSEC, CAA, auditoria de registros antigos | Consulta WHOIS, Verificação de saúde DNS, Localizador de Subdomínios |
| 2. Transporte (TLS) | Rebaixam a conexão para HTTP, removem a criptografia, exploram cifras antigas, certificados expirados | TLS 1.2+, HSTS (preload opcional), renovação automatizada | Verificador de SSL |
| 3. Cabeçalhos HTTP | Injetam scripts (XSS), colocam o site em frames para clickjacking, farejam tipos de conteúdo, vazam o referrer | CSP, frame-ancestors, nosniff, Referrer-Policy, Permissions-Policy | Verificador de Cabeçalhos HTTP |
| 4. Aplicação | Credential stuffing, injeção, controle de acesso quebrado, CSRF, uploads inseguros | Argon2id + MFA + rate limits, consultas parametrizadas, autorização no servidor, cookies SameSite | Revisão de código, ZAP, Testador de Força de Senha |
| 5. Dependências | Pacotes envenenados, CVEs conhecidas em bibliotecas, pipelines de CI comprometidos | Lockfiles, auditorias, versões fixadas, SBOM, tokens com privilégio mínimo | npm audit, Dependabot, Trivy |
| 6. Servidor e operações | Portas abertas, credenciais padrão, patches ausentes, nenhum backup, nenhum log | Firewall, SSH só com chave, aplicação de patches, backups 3-2-1, logs centralizados | Verificador de Portas, Verificador de Blacklist de IP |
Trabalhe de cima para baixo. As camadas 1 a 3 são configurações que você termina em uma tarde, e elas protegem todas as páginas de uma vez. As camadas 4 a 6 são hábitos contínuos, que precisam fazer parte da sua revisão de código e do seu processo de deploy.
Camada 1: blinde o domínio e o DNS
Todo o resto deste guia pressupõe que você ainda controla o seu domínio. Se um atacante conseguir entrar no seu registrador ou trocar os seus nameservers, ele pode apontar o seu tráfego para qualquer lugar, obter um certificado válido para o seu nome e ler todos os e-mails enviados a você, sem que nenhuma linha do código da sua aplicação chegue a rodar. Por isso, a segurança do domínio e do DNS é a primeira das boas práticas de segurança web, e ela é quase toda feita de configuração.
Comece com uma consulta WHOIS do seu próprio domínio e confirme três coisas: os códigos de status incluem clientTransferProhibited, a data de expiração está a mais de um ano de distância e o registrador é um em que você de fato tem conta. É surpreendentemente comum o domínio de uma empresa estar parado na conta de registrador de um ex-prestador de serviços. Nosso guia de consulta WHOIS explica cada código de status que você vai encontrar.
Registrar lock, MFA e alertas de expiração
Ative o registrar lock (também chamado de bloqueio de transferência) para que o domínio não possa ser levado para outro registrador sem que você o desbloqueie explicitamente, e ative a autenticação multifator na própria conta do registrador. Contas de registrador são alvo preferido de phishing justamente porque um único login controla tudo o que vem depois. Use uma chave de segurança física ou um app autenticador em vez de SMS sempre que o registrador permitir.
Configure o domínio para renovar automaticamente com uma forma de pagamento que não vença e, mesmo assim, adicione um alerta no calendário 60 dias antes da data de expiração. Um domínio vencido não é perdido no dia em que expira, mas, esgotados os períodos de carência e de resgate (até cerca de 80 dias para .com), ele é excluído, e serviços de drop-catch o registram em segundos após a liberação. O comprador herda o seu e-mail, o seu tráfego e quaisquer logins OAuth que confiem no seu domínio.
- O registry lock (um bloqueio manual, fora de banda, no nível do registro) vale a taxa extra para um domínio do qual uma empresa depende; ele impede que até uma conta de registrador comprometida troque os nameservers.
- Separe as funções. Quem paga pelo domínio, a conta que é dona dele e o provedor de DNS devem estar documentados e não podem depender da caixa de e-mail de um único funcionário.
- Ative a privacidade do WHOIS para que os seus dados de contato não virem um mapa para phishing, e mantenha na conta um endereço de função monitorado, como
domains@.
Assine a zona com DNSSEC
O DNSSEC assina a sua zona DNS para que um resolvedor possa detectar respostas forjadas. Sem ele, um atacante que consiga envenenar o cache de um resolvedor pode enviar seus visitantes a um servidor falso enquanto o navegador continua mostrando o seu nome de domínio. A maioria dos provedores de DNS gerenciado (Cloudflare, Route 53, Google Cloud DNS e muitos registradores) ativa isso com um único botão; o único passo manual é publicar o registro DS no seu registrador. Verifique com dig ou com a Verificação de saúde DNS, que confere o registro DS e as assinaturas:
dig +dnssec +short yourdomain.com A
# A signed zone returns the record AND an RRSIG line:
# 203.0.113.10
# A 13 2 3600 20270115000000 20261225000000 34505 yourdomain.com. Kx3f...==
dig +short yourdomain.com DS
# A DS record at the parent zone proves the chain of trust is complete
# 2371 13 2 6A1B...C9Restrinja a emissão de certificados com CAA
Um registro CAA (RFC 8659) informa às autoridades certificadoras quais delas podem emitir certificados para o seu domínio. Toda CA pública é obrigada a consultá-lo antes de emitir, então um registro CAA fecha a porta para um atacante que tenha enganado a validação de domínio de alguma outra CA. Três registros cobrem os casos comuns: quem pode emitir, quem pode emitir certificados wildcard e para onde reportar uma solicitação recusada:
yourdomain.com. CAA 0 issue "letsencrypt.org"
yourdomain.com. CAA 0 issuewild ";"
yourdomain.com. CAA 0 iodef "mailto:security@yourdomain.com"Audite registros antigos: subdomain takeover
Um subdomain takeover (tomada de subdomínio) acontece quando um registro DNS ainda aponta para um serviço que você parou de usar: um CNAME para um site do GitHub Pages excluído, um app do Azure, um bucket do S3 ou o hostname de um fornecedor SaaS. Qualquer pessoa pode registrar o destino abandonado e servir conteúdo em old-app.yourdomain.com em seu nome, com certificado válido. É uma descoberta frequente em programas de bug bounty porque ninguém lembra que o registro existe.
Passe o seu domínio pelo Localizador de Subdomínios: ele consulta dois serviços de logs de transparência de certificados, o Cert Spotter (certificados atuais) e o crt.sh (todos os certificados desde 2013), testa 1.000 nomes comuns, resolve cada nome ao vivo, marca CNAMEs órfãos e mostra qual host ou CDN executa cada um. Exclua todo registro cujo destino retorne NXDOMAIN ou uma página "no such app" do provedor; uma consulta DNS confirma um nome específico. Repita a cada trimestre e faça da exclusão do registro DNS parte do descomissionamento de qualquer serviço.
A certificate transparency também é o seu sistema de alerta precoce: o Cert Spotter e o monitoramento de CT da Cloudflare podem avisar você por e-mail sempre que qualquer CA emitir um certificado para o seu domínio. Um certificado inesperado costuma ser o primeiro sinal visível de que o DNS ou o registrador foi comprometido.
Camada 2: HTTPS e TLS bem configurados
HTTPS não é mais uma boa prática, é o básico, e os navegadores marcam páginas HTTP simples como "Não seguro". O Google também anunciou que, a partir do Chrome 154 (outubro de 2026), o navegador pergunta antes de abrir qualquer site público por HTTP simples (Google). O que ainda separa um site seguro de um site apenas criptografado são as versões de TLS aceitas, se é possível chegar até você por HTTP e se a renovação é automatizada o bastante para sobreviver aos cortes de validade dos certificados iniciados em março de 2026.
TLS 1.2 no mínimo, TLS 1.3 de preferência
O TLS 1.0 e o 1.1 foram oficialmente descontinuados pela RFC 8996 em 2021, e nenhum navegador atual os negocia. Desative-os no servidor, dê preferência ao TLS 1.3 (que elimina todas as cifras fracas conhecidas e conclui o handshake em uma única ida e volta) e mantenha o TLS 1.2 apenas com cipher suites AEAD, como ECDHE-ECDSA-AES128-GCM-SHA256 ou ECDHE-RSA-CHACHA20-POLY1305.
Duas linhas importam quando você testa de fora: o protocolo negociado e Verify return code: 0, que significa que toda a cadeia de certificados foi validada. Um certificado intermediário ausente é uma causa comum dos relatos "funciona no Chrome, falha no curl e no Android"; nosso guia sobre a cadeia de certificados SSL mostra como corrigir, e o Verificador de SSL sinaliza diretamente uma cadeia incompleta. Aqui está a verificação executada contra dnsrobot.net em 27 de outubro de 2026, e depois um teste para ver se o servidor recusa TLS 1.1:
echo | openssl s_client -connect dnsrobot.net:443 -servername dnsrobot.net 2>/dev/null \
| grep -E 'Protocol|Cipher|Verify return'
# New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
# Protocol: TLSv1.3
# Verify return code: 0 (ok)
# Is TLS 1.1 refused? SECLEVEL=0 lets OpenSSL 3 and later offer it at all
openssl s_client -connect example.com:443 -servername example.com -tls1_1 \
-cipher 'DEFAULT:@SECLEVEL=0' </dev/null 2>&1 | grep -E 'alert|Cipher is'
# Refused, as it should be: ...tlsv1 alert protocol version...
# New, (NONE), Cipher is (NONE)
# Still accepted (fix it): New, TLSv1.0, Cipher is ECDHE-ECDSA-AES128-SHA
# (TLSv1.0 is the cipher's version; the handshake was TLS 1.1)Listas de cifras são onde configurações copiadas e coladas ficam desatualizadas. Em vez de escrevê-las à mão, gere o bloco de servidor recomendado atual para nginx, Apache, Caddy ou HAProxy com o Mozilla SSL Configuration Generator e escolha o perfil "Intermediate", a menos que você precise dar suporte a clientes muito antigos.
HSTS: nunca mais deixe o navegador usar HTTP
Redirecionar HTTP para HTTPS não basta por si só. A primeiríssima requisição que um visitante faz para http://yourdomain.com ainda trafega em texto puro, e um atacante na mesma rede pode respondê-la antes do seu redirecionamento. O HTTP Strict Transport Security (RFC 6797) resolve isso: depois que o navegador vê o cabeçalho, ele reescreve toda URL http:// futura do seu domínio para https:// antes de enviar qualquer coisa.
Use um max-age de pelo menos um ano (31536000 segundos) e adicione includeSubDomains quando todos os subdomínios servirem HTTPS. O preload em hstspreload.org, que embute o domínio no Chrome, Firefox, Safari e Edge, é opcional: os próprios mantenedores da lista dizem agora que o HSTS é recomendado, mas o preload não, porque o Chrome e o Safari já elevam as navegações para HTTPS e sair da lista leva meses. Verifique o cabeçalho com o Verificador de Cabeçalhos HTTP, que pontua o HSTS com os testes do Mozilla HTTP Observatory.
Strict-Transport-Security: max-age=31536000; includeSubDomainsCertificados de 47 dias: automatize a renovação já
A votação SC-081 do CA/Browser Forum está reduzindo em etapas a validade máxima de todo certificado TLS público. O primeiro corte entrou em vigor em 15 de março de 2026, então qualquer certificado que você compre ou renove hoje já está limitado a 200 dias, e em 2029 um certificado precisará ser substituído mais ou menos a cada seis semanas:
| Data de vigência | Validade máxima do certificado | Reutilização da validação de domínio |
|---|---|---|
| Antes de 15 de março de 2026 | 398 dias | 398 dias |
| 15 de março de 2026 | 200 dias | 200 dias |
| 15 de março de 2027 | 100 dias | 100 dias |
| 15 de março de 2029 | 47 dias | 10 dias |
A renovação manual não sobrevive a esse cronograma. A boa prática é a emissão totalmente automatizada via ACME: Let's Encrypt ou Google Trust Services por meio do certbot, acme.sh, Caddy ou dos certificados automáticos embutidos na Cloudflare, Vercel, Netlify e na maioria dos painéis de hospedagem. Teste o caminho de renovação antes de precisar dele (certbot renew --dry-run no certbot); a falha a procurar é um registro CAA ou uma regra de firewall adicionada desde a última renovação que agora bloqueia a validação. Seja qual for a ferramenta, monitore também a data de expiração de fora: o Verificador de SSL mostra os dias restantes, e um certificado expirado transforma cada visita em um aviso de página inteira do navegador.
Camada 3: cabeçalhos de segurança HTTP
Cabeçalhos de segurança são instruções que o seu servidor dá ao navegador sobre o que ele pode ou não fazer com as suas páginas: quais scripts podem rodar, se a página pode ser colocada em um frame, se o navegador pode adivinhar tipos de conteúdo e o que ele deve contar a outros sites sobre de onde veio o visitante. Não custam nada, valem para todas as páginas de uma vez e bloqueiam classes inteiras de ataques. Também são a camada que a maioria dos sites acerta só em parte, e por isso o Verificador de Cabeçalhos HTTP os pontua com os testes do Mozilla HTTP Observatory. Aqui está o que o github.com enviou em 27 de outubro de 2026, reduzido aos cabeçalhos de segurança (o script-src dele cita um host de recursos e um hash de script, sem 'unsafe-inline'):
curl -sI https://github.com/ | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy'
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
content-security-policy: default-src 'none'; base-uri 'self'; ... frame-ancestors 'none'; ... script-src github.githubassets.com 'sha256-6AKuI+cDd1MoUL1u4eqrA9PXmnPAkOB4h7421hPUUm0='; ...Os sete cabeçalhos que todo site deve enviar
Estes são os valores a buscar em um site típico. Na pontuação do Mozilla HTTP Observatory, que o nosso Verificador de Cabeçalhos HTTP usa, a falta de CSP custa 25 pontos, a falta de HSTS ou de proteção contra framing custa 20 cada, e a falta de nosniff custa 5; Referrer-Policy e COOP somam pontos de bônus enquanto a pontuação ainda for 90 ou mais. A Permissions-Policy não é pontuada (só navegadores Chromium a leem), mas ainda vale definir.
| Cabeçalho | Valor recomendado | O que ele previne |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Downgrade de protocolo, roubo de cookies via HTTP |
Content-Security-Policy | script-src baseado em nonce com 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none' | Cross-site scripting (XSS), injeção de dados, clickjacking |
X-Content-Type-Options | nosniff | MIME sniffing que transforma um upload em script executável |
Referrer-Policy | strict-origin-when-cross-origin | Vazamento de URLs completas (tokens, termos de busca) para terceiros |
Permissions-Policy | camera=(), microphone=(), geolocation=(), payment=() | Scripts de terceiros usando em silêncio APIs poderosas do navegador |
X-Frame-Options | DENY (fallback legado para frame-ancestors) | Clickjacking em navegadores sem CSP Level 2 |
Cross-Origin-Opener-Policy | same-origin | Ataques entre janelas por meio de window.opener |
Content Security Policy sem quebrar o site
Uma Content Security Policy é a defesa mais eficaz contra XSS, porque impede que scripts injetados sejam executados mesmo quando existe uma falha de injeção. O problema é que uma política rígida quebra qualquer script inline ou tag de terceiros que você tenha esquecido. A abordagem moderna, recomendada pelo Google e documentada no MDN, é uma política baseada em nonce: o servidor gera um nonce aleatório a cada resposta, coloca esse nonce em toda tag de script que renderiza intencionalmente, e o navegador recusa todo o resto.
O 'strict-dynamic' é o que torna a política viável: um script com nonce pode carregar outros scripts (analytics, gerenciadores de tags, widgets) sem que cada um precise estar na allowlist, enquanto os tokens https: e 'unsafe-inline' são ignorados pelos navegadores modernos e servem apenas de fallback para os antigos. Implante primeiro com Content-Security-Policy-Report-Only, acompanhe os relatórios de violação por uma semana e depois passe para o modo de bloqueio. Frameworks como Next.js, Rails e Django têm suporte nativo a nonce; sites estáticos podem usar um script-src baseado em hash.
Content-Security-Policy:
script-src 'nonce-r4nd0m1z3dV4lu3' 'strict-dynamic' https: 'unsafe-inline';
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
form-action 'self';
report-to csp-endpoint
<!-- Only scripts carrying the nonce run; strict-dynamic lets them load their own dependencies -->
<script nonce="r4nd0m1z3dV4lu3" src="/app.js"></script>Uma política de allowlist como script-src 'self' https://cdn.example.com é melhor do que nada, mas qualquer endpoint JSONP ou biblioteca antiga em um host liberado pode ser usado para contorná-la. Se você ainda não pode usar nonces, defina pelo menos object-src 'none' e base-uri 'none', que fecham na hora duas formas comuns de bypass.
Clickjacking: frame-ancestors e X-Frame-Options
O clickjacking carrega o seu site de forma invisível dentro da página de um atacante e induz o visitante a clicar em um botão que ele não consegue ver. frame-ancestors 'none' na CSP (ou 'self', se você incorpora as suas próprias páginas) impede isso em todos os navegadores atuais, e X-Frame-Options: DENY cobre os mais antigos. Se você oferece de propósito um widget incorporável, libere apenas esse caminho e apenas para as origens que precisam dele; nosso guia de X-Frame-Options mostra as regras exatas de servidor e os erros "refused to connect" que você vai encontrar durante os testes.
nosniff, Referrer-Policy, Permissions-Policy e COOP
X-Content-Type-Options: nosniff impede que o navegador tente adivinhar além do Content-Type, que é o que transforma uma "imagem" enviada por um usuário, mas contendo HTML, em uma página executável. Referrer-Policy: strict-origin-when-cross-origin (o padrão nos navegadores atuais, mas defina explicitamente) envia apenas a sua origem para outros sites, de modo que tokens de redefinição de senha e termos de busca nas URLs continuem privados. Permissions-Policy desativa recursos do navegador que você não usa, para que um script de terceiros comprometido não consiga abrir a câmera nem ler a localização. Cross-Origin-Opener-Policy: same-origin corta o vínculo window.opener com as páginas que você abre, o que bloqueia uma classe de ataques entre janelas.
Os cabeçalhos a remover também importam: Server e X-Powered-By anunciam a scanners de vulnerabilidade as versões exatas do software, e X-XSS-Protection está obsoleto e pode introduzir bugs em navegadores antigos, então defina-o como 0 ou remova-o. O Detector de CMS mostra o que qualquer pessoa pode descobrir sobre a sua stack e as versões dela a partir da própria página.
Defina os cabeçalhos uma única vez na borda (CDN, proxy reverso ou middleware do framework), e não página por página. No Next.js, isso fica no arquivo de proxy ou de middleware; no nginx, em um bloco add_header no contexto do servidor; no Apache, com Header always set. Depois, rode de novo o Verificador de Cabeçalhos HTTP a cada deploy, porque uma nova versão do framework ou uma configuração da CDN pode remover um deles sem aviso.
Camada 4: autenticação que resiste ao credential stuffing
Atacantes raramente adivinham senhas uma a uma. Eles reaproveitam bilhões de pares de e-mail e senha vazados de outros sites (credential stuffing) e conseguem o resto por phishing. Por isso, a boa prática de autenticação tem três partes: armazenar senhas de modo que um vazamento do banco de dados não seja um vazamento de senhas, tornar uma senha roubada inútil por si só e deixar a força bruta lenta demais para fazer diferença. A OWASP classifica Authentication Failures (falhas de autenticação) em A07 no OWASP Top 10:2025.
Faça o hash de senhas com Argon2id ou bcrypt
Nunca armazene uma senha, e nunca armazene um hash rápido dela. MD5, SHA-1 e até SHA-256 foram projetados para ser rápidos, então uma tabela vazada com esses hashes pode ser testada a bilhões de tentativas por segundo em uma única GPU. Use uma função de hash de senhas lenta e que exija muita memória, com um salt único por senha. O OWASP Password Storage Cheat Sheet recomenda, nesta ordem:
- Argon2id com pelo menos 19 MiB de memória, 2 iterações e grau de paralelismo 1 (ou 46 MiB com 1 iteração).
- scrypt com N = 2^17, r = 8, p = 1 onde o Argon2 não estiver disponível.
- bcrypt com fator de trabalho 10 ou mais (atenção ao limite de entrada de 72 bytes; fazer pré-hash de senhas mais longas exige cuidado).
- PBKDF2-HMAC-SHA256 com 600.000 iterações, apenas quando a conformidade com FIPS exigir.
// Node.js with the argon2 package
import argon2 from "argon2";
const hash = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 19456, // KiB = 19 MiB
timeCost: 2,
parallelism: 1,
});
// Later, on login:
const ok = await argon2.verify(hash, submittedPassword);Ajuste o custo para que um hash leve cerca de 100 a 250 ms no seu servidor de login. Isso é imperceptível para um usuário real, mas limita cada núcleo de CPU a um punhado de tentativas por segundo e até uma placa de vídeo topo de linha a milhares em vez de bilhões. Refaça o hash a cada login bem-sucedido sempre que aumentar os parâmetros, para que os hashes antigos se atualizem sozinhos.
Regras de senha que realmente ajudam (NIST SP 800-63B)
As regras de composição que a maioria dos sites ainda impõe (uma letra maiúscula, um símbolo, troca a cada 90 dias) produzem senhas previsíveis como Summer2026! e levam as pessoas a reutilizá-las. As diretrizes atuais do NIST SP 800-63B as substituem por regras que medem o que importa:
- Mínimo de 8 caracteres quando o MFA também é exigido, e pelo menos 15 caracteres para uma senha usada sozinha; permita pelo menos 64.
- Nada de regras de composição e nada de troca periódica obrigatória; exija a troca apenas quando houver evidência de comprometimento.
- Confira toda senha nova em uma lista de vazamentos (a API de intervalos do Have I Been Pwned permite fazer isso sem enviar a senha) e rejeite as que já vazaram.
- Permita colar e usar gerenciadores de senhas, aceite espaços e Unicode e dê orientações que ajudem a escolher uma senha forte, especialmente logo depois de rejeitar uma.
Nosso Testador de Força de Senha mostra como essas medidas diferem das regras antigas: ele estima quanto tempo uma senha leva para ser quebrada sob 8 ataques nomeados, mostra os padrões que a enfraquecem e a compara com dados de vazamentos sem enviar a senha, um retorno muito mais útil do que uma mensagem vermelha de "precisa de um símbolo".
MFA e passkeys
A autenticação multifator transforma uma senha roubada em um beco sem saída. Ofereça para todos e exija para os perfis de administração, financeiro e suporte. Classifique as opções pela resistência a phishing: passkeys e chaves de segurança FIDO2 não podem ser alvo de phishing porque a credencial fica vinculada à sua origem real; apps autenticadores (TOTP) são bons; códigos por SMS são melhores do que nada, mas podem ser interceptados via SIM swap. As passkeys são suportadas por todos os navegadores e sistemas operacionais atuais e eliminam a senha por completo, o que também elimina o credential stuffing como categoria.
Proteja o caminho de recuperação com o mesmo cuidado que o login: códigos de recuperação armazenados como hash, redefinições por e-mail com tokens de uso único que expiram em até 15 minutos e nada de perguntas de segurança.
Rate limiting, bloqueio de conta e defesa contra bots
Aplique rate limiting aos endpoints de login, cadastro, redefinição de senha e MFA por IP e por conta, e retorne 429 Too Many Requests com um cabeçalho Retry-After quando o limite for atingido (nosso guia sobre o erro HTTP 429 explica como os clientes devem reagir). Combine isso com um atraso crescente ou um bloqueio temporário após falhas repetidas em uma mesma conta, e com um CAPTCHA ou desafio de proof-of-work nos endpoints que sofrem ataques distribuídos. Registre todo login com falha junto com o IP de origem, para que o padrão de uma rodada de credential stuffing fique visível em minutos, e não em meses.
# nginx: 5 login attempts at once, then 1 every 12 seconds, per client IP
# (limit_req sends no Retry-After header; add one on your 429 page if clients need it)
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
location = /api/login {
limit_req zone=login burst=4 nodelay;
limit_req_status 429;
proxy_pass http://app;
}Mantenha mensagens de erro idênticas para "usuário desconhecido" e "senha incorreta", e faça o tempo de resposta ser o mesmo nos dois casos (calcule o hash de uma senha fictícia quando o usuário não existir). Caso contrário, o formulário de login vira também uma API de enumeração de usuários.
Sessões, cookies e CSRF
Depois do login, o cookie de sessão é o usuário, então ele merece a mesma proteção que a senha. Três atributos de cookie e um prefixo de nome fazem a maior parte do trabalho:
Securesignifica que o cookie nunca é enviado por HTTP puro, então ele não pode ser capturado em um Wi-Fi público.HttpOnlydeixa o cookie invisível para o JavaScript, então uma falha de XSS não consegue lê-lo.SameSite=Lax(ouStrictpara painéis de administração) mantém o cookie fora de requisições POST entre sites, o que neutraliza a maioria dos ataques CSRF.- O prefixo
__Host-faz o navegador recusar o cookie a menos que ele sejaSecure, tenhaPath=/e não tenha o atributoDomain, para que um subdomínio não consiga sobrescrevê-lo.
Set-Cookie: __Host-session=9f1c7e2a...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800Ações que alteram estado nunca devem ser acessíveis via GET. Um link como /account/delete?id=42 pode ser disparado por uma tag <img> em qualquer página que o usuário visite, por melhores que sejam as flags dos seus cookies.
CSRF: uma segunda linha de defesa além do SameSite
O cross-site request forgery (CSRF) engana um navegador logado para que ele envie ao seu site, a partir de outra página, uma requisição que altera estado. Cookies SameSite impedem o caso comum, mas mantenha uma segunda defesa em toda requisição que não seja GET: um token anti-CSRF por sessão em um campo oculto ou em um cabeçalho personalizado, ou uma verificação de que o cabeçalho Origin (ou Sec-Fetch-Site) corresponde à sua própria origem. A maioria dos frameworks (Django, Rails, Laravel, server actions do Next.js) faz isso por padrão; o erro é desativar a proteção em um endpoint de API e depois chamar esse endpoint a partir de um navegador.
IDs de sessão, rotação e JWTs
Gere IDs de sessão com pelo menos 128 bits de aleatoriedade, troque o ID no login e em qualquer mudança de privilégio para neutralizar a fixação de sessão, expire as sessões após um período de inatividade e dê aos usuários um botão "sair de todos os dispositivos" que as invalide no servidor. Com JWTs, mantenha-os de curta duração (minutos, com um refresh token que possa ser revogado), nunca os armazene no localStorage, onde qualquer script consegue lê-los, e trate o vazamento de uma chave de assinatura como uma violação completa, porque todo token que ela já assinou agora pode ser forjado.
Injeção e XSS: valide a entrada, codifique a saída
A Injection (injeção, A05:2025) e o cross-site scripting são o mesmo erro em lugares diferentes: dados vindos de um usuário são entregues a um interpretador (SQL, o shell, uma consulta LDAP, uma página HTML) como se fossem código. A correção também é a mesma em todo lugar: mantenha dados e código separados e nunca monte um comando concatenando strings.
Consultas parametrizadas, não concatenação de strings
Em SQL, use prepared statements ou um ORM que os gere; o banco de dados passa a tratar a entrada como um valor que nunca pode alterar a estrutura da consulta. A mesma regra vale para comandos de shell (passe um array de argumentos, nunca uma string), para filtros NoSQL (rejeite objetos de operador como {"$gt": ""} na entrada do usuário) e para caminhos de arquivo (resolva o caminho e confirme que ele permanece dentro do diretório pretendido).
// Vulnerable: the input becomes part of the query text
const rows = await db.query(`SELECT * FROM users WHERE email = '${email}'`);
// Safe: the driver sends the value separately from the query
const rows = await db.query("SELECT * FROM users WHERE email = $1", [email]);
// Python / psycopg: same idea
cur.execute("SELECT * FROM users WHERE email = %s", (email,))Codificar a saída impede o XSS
O cross-site scripting acontece quando um texto controlado pelo usuário é escrito em uma página sem a codificação adequada ao contexto em que ele cai. Os template engines modernos (React e JSX, Vue, Jinja2, Blade, ERB) codificam por padrão; hoje, o XSS costuma vir das válvulas de escape: dangerouslySetInnerHTML, v-html, |safe, innerHTML e a montagem de URLs ou event handlers inline a partir de dados do usuário. Codifique para o contexto exato e sanitize HTML rico com uma biblioteca feita para isso, como o DOMPurify, em vez de uma regex.
| Onde os dados caem | Codifique como | Exemplo |
|---|---|---|
| Corpo do HTML | Entidades HTML | < vira <, " vira " |
| Atributo HTML | Entidades, com o atributo entre aspas | Sempre coloque o atributo entre aspas; codifique " e ' |
| JavaScript | Não injete no texto do script; passe os dados por atributos data- ou por um bloco JSON <script type="application/json"> | </script> dentro de uma string vira \u003c/script\u003e |
| Parâmetro de URL | Percent-encoding | encodeURIComponent(value) |
| Valor CSS | Evite totalmente; escolha nomes de classe de uma allowlist | Nunca interpole entrada do usuário em style |
SSRF, upload de arquivos e desserialização
Server-side request forgery (SSRF): se o seu servidor busca uma URL fornecida por um usuário (webhooks, proxies de imagem, pré-visualizações de links), um atacante pode apontá-la para serviços internos ou para o endpoint de metadados da nuvem 169.254.169.254 e ler credenciais. Resolva o hostname primeiro, rejeite faixas privadas e link-local, desative redirecionamentos e coloque os serviços que fazem essas buscas em um segmento de rede que não alcance nada interno.
Upload de arquivos: valide o tipo inspecionando o conteúdo, e não a extensão nem o Content-Type informado pelo cliente; imponha um limite de tamanho; armazene os arquivos fora da raiz web ou em object storage, com um nome aleatório gerado por você; e sirva-os a partir de uma origem separada com nosniff e Content-Disposition: attachment sempre que possível. Nunca deixe um upload cair em um lugar onde o servidor web vá executá-lo.
Desserialização e mass assignment: nunca desserialize dados não confiáveis com um formato capaz de instanciar classes arbitrárias (serialização nativa do Java, pickle do Python, unserialize do PHP, YAML com tags personalizadas); use JSON com um schema. Vincule os corpos das requisições a uma allowlist explícita de campos, para que um usuário não consiga enviar via POST "role": "admin" para um modelo que por acaso tenha essa coluna.
Broken Access Control: o risco número um
O Broken Access Control (controle de acesso quebrado) ocupa o primeiro lugar do OWASP Top 10 desde 2021 e continua nele como A01:2025. Não é um bug isolado, mas um hábito: verificar quem a pessoa é (autenticação) e esquecer de verificar o que ela pode acessar (autorização) em cada requisição. A forma clássica é a referência direta insegura a objeto (IDOR): GET /api/invoices/1042 funciona para o dono da fatura e também para qualquer pessoa que troque o número.
- Negue por padrão. Toda rota exige uma regra explícita que conceda acesso; uma regra ausente significa 403, não 200.
- Imponha no servidor, objeto por objeto. Esconder um botão na interface não é controle de acesso. Toda leitura e escrita deve confirmar que o usuário atual é dono do registro específico ou tem permissão sobre ele, inclusive em endpoints em lote, exportações e jobs em segundo plano.
- Use IDs impossíveis de adivinhar quando isso ajudar (UUIDs), mas nunca dependa deles: obscuridade não é autorização.
- Restrinja o CORS.
Access-Control-Allow-Origin: *com credenciais, ou refletir qualquerOriginque a requisição envie, entrega a sua API a qualquer site que o usuário visite. - Desative a listagem de diretórios, bloqueie
.git,.env, arquivos de backup e de configuração no nível do servidor web e mantenha os painéis de administração fora da internet pública ou protegidos por MFA e allowlists de IP. - Aplique rate limiting e registre as falhas de autorização. Uma rajada de 403 vinda de uma única sessão é um ataque de enumeração em andamento.
// Express: ownership check on every object access
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
const invoice = await Invoice.findById(req.params.id);
if (!invoice || invoice.ownerId !== req.user.id) {
return res.status(404).end(); // 404, not 403: don't confirm the record exists
}
res.json(invoice);
});Camada 5: dependências e a cadeia de suprimentos de software
A maior parte do código de uma aplicação web típica é código baixado, não escrito por você. Por isso as falhas na cadeia de suprimentos de software estreiam em A03 no OWASP Top 10 de 2025, e por isso a exploração de vulnerabilidades superou o phishing e as credenciais roubadas no DBIR 2026. Em setembro de 2025, um único mantenedor vítima de phishing colocou malware que rouba criptomoedas em chalk, debug e outros 16 pacotes npm que somam mais de dois bilhões de downloads por semana; todo projeto que instalou uma versão não fixada durante essa janela o puxou automaticamente.
- Faça commit de um lockfile (
package-lock.json,yarn.lock,pnpm-lock.yaml,poetry.lock,go.sum) e instale comnpm cino CI, para que os builds sejam reproduzíveis e uma nova versão upstream não entre sem revisão. - Escaneie continuamente:
npm audit,pip-audit,bundler-audit, GitHub Dependabot ou Renovate para as atualizações e um scanner de contêineres como Trivy ou Grype para a camada do sistema operacional. - Adie as atualizações que não são de segurança por alguns dias (o
minimumReleaseAgedo Renovate), para que uma versão envenenada normalmente seja retirada antes de você adotá-la, mas aplique os patches de segurança imediatamente. - Fixe actions e scripts de terceiros no SHA de um commit no CI e use Subresource Integrity (
integrity="sha384-...") em todo script que você carrega de uma CDN pública. - Dê ao CI o menor privilégio possível: tokens somente leitura sempre que der, credenciais OIDC de curta duração em vez de segredos de longa duração e direitos de publicação limitados a um job de release.
- Gere um SBOM (CycloneDX ou SPDX) no momento do build, para responder "fomos afetados?" em minutos quando chegar a próxima CVE do porte do Log4Shell.
# Reproducible install + audit in CI
npm ci --ignore-scripts
npm audit --audit-level=high
# Pin a GitHub Action to a commit, not a floating tag
# uses: actions/checkout@v4 <- can change underneath you
# uses: actions/checkout@<full-commit-sha> # v4.2.2
# Subresource Integrity for a CDN script (hash from: openssl dgst -sha384 -binary lib.min.js | openssl base64 -A)
<script src="https://cdn.example.com/lib.min.js"
integrity="sha384-<base64-hash>"
crossorigin="anonymous"></script>npm ci --ignore-scripts bloqueia os scripts de instalação que a maioria dos malwares do npm usa para rodar; depois, reative os scripts apenas para os poucos pacotes que realmente precisam de uma etapa de build.
Se você usa WordPress ou outro CMS, as mesmas regras valem para plugins e temas, que é por onde começa a maioria dos comprometimentos de CMS. Mantenha o core e todos os plugins atualizados, exclua os que você não usa e veja o que um scanner consegue descobrir sobre as suas versões com o Detector de CMS.
Camada 6: hardening do servidor (portas, patches, segredos, backups)
A camada da aplicação não importa se o servidor por baixo aceita login por senha no SSH, roda um banco de dados em uma porta pública ou não recebe patches desde que foi montado. As boas práticas de servidor são entediantes, e é por elas que o ransomware entra.
Feche todas as portas que você não usa
Um servidor web público precisa das portas 80 e 443 abertas, e do SSH liberado apenas para a sua própria faixa de IPs. Bancos de dados (3306, 5432, 27017), Redis (6379), Elasticsearch (9200), painéis de administração e endpoints de métricas devem escutar apenas em localhost ou em uma rede privada. Confira de fora com o Verificador de Portas após cada mudança, porque essa é a visão que um atacante tem, e é fácil interpretar errado os security groups da nuvem.
# Ubuntu: default-deny firewall, allow only web + SSH from your office range
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp
sudo ufw enable # check your own IP is in that range first, or you lock yourself out
# SSH: keys only, no root password login, in a drop-in that sshd reads first
printf 'PasswordAuthentication no\nPermitRootLogin prohibit-password\n' \
| sudo tee /etc/ssh/sshd_config.d/00-hardening.conf
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin) ' # what sshd will really use
sudo systemctl reload sshNo Ubuntu e no Debian, o sshd lê os arquivos de /etc/ssh/sshd_config.d/ antes do restante do sshd_config, e para cada configuração vale o primeiro valor lido. É por isso que os comandos acima gravam um drop-in chamado 00-hardening.conf: uma edição mais abaixo no arquivo principal perde para o drop-in de uma imagem de nuvem que diz PasswordAuthentication yes. Confirme o resultado com sudo sshd -T antes de sair. No Verificador de Portas, uma porta que o seu firewall descarta aparece como filtered (sem resposta), e uma sem nenhum serviço escutando aparece como closed: ambas estão bem, open é a que precisa ser corrigida.
Aplique patches com regularidade e tire os segredos do código
Ative as atualizações de segurança automáticas do sistema operacional, assine as listas de segurança do seu runtime e do seu framework e trate uma CVE crítica em qualquer coisa exposta à internet como tarefa para o mesmo dia. Rode os serviços com usuários sem privilégios, em contêineres ou com o sandboxing do systemd, para que um processo comprometido não consiga ler a máquina inteira.
Segredos (senhas de banco de dados, chaves de API, chaves de assinatura) nunca devem ficar no repositório, em uma camada de imagem Docker ou no JavaScript do lado do cliente. Carregue-os de variáveis de ambiente injetadas no deploy ou de um gerenciador de segredos, troque-os quando alguém com acesso sair da equipe e escaneie o histórico do repositório com uma ferramenta como o gitleaks, porque uma chave commitada uma única vez está comprometida para sempre, mesmo depois que o commit é removido.
Backups que sobrevivem ao ransomware, e uma CDN na frente
Siga a regra 3-2-1: três cópias, em duas mídias diferentes, uma fora do local, e deixe pelo menos uma cópia imutável ou offline, para que um ransomware que chegue ao servidor não consiga criptografar também os backups. Criptografe os backups, inclua o banco de dados e o diretório de uploads e, o mais importante, teste uma restauração periodicamente. Um backup que ninguém nunca restaurou é uma esperança, não um plano. O tempo de recuperação é o que decide se um incidente será uma simples indisponibilidade ou um evento capaz de acabar com a empresa.
Coloque uma CDN ou WAF (Cloudflare, Fastly, AWS CloudFront com WAF ou o equivalente da sua hospedagem) na frente da origem. Ela absorve DDoS volumétrico, aplica regras gerenciadas contra payloads comuns de injeção e bots maliciosos, esconde o IP da sua origem e dá a você um lugar para aplicar limites de requisições e regras geográficas sem mexer na aplicação. Depois restrinja o firewall da origem para que só as faixas de IP da CDN alcancem a porta 443 diretamente; do contrário, os atacantes simplesmente a contornam. O Verificador de Hospedagem mostra qual CDN fica na frente de um site e o que as evidências públicas dizem sobre o host por trás.
Autenticação de e-mail: SPF, DKIM e DMARC
A segurança web inclui o e-mail que carrega suas redefinições de senha, faturas e respostas de suporte. Sem SPF, DKIM e DMARC, qualquer pessoa pode enviar e-mail como billing@yourdomain.com, e desde fevereiro de 2024 o Google e o Yahoo exigem os três de remetentes em massa, e a Microsoft faz o mesmo para o Outlook.com desde maio de 2025. O conjunto completo são três registros TXT de DNS:
yourdomain.com. TXT "v=spf1 include:_spf.google.com -all"
google._domainkey.yourdomain.com. TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
_dmarc.yourdomain.com. TXT "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s"O DMARC p=reject também é um controle de proteção de marca: é a única coisa que impede uma campanha de phishing de colocar exatamente o seu domínio no campo From. Os relatórios agregados (rua=) mostram quem está tentando.
Comece o DMARC em p=none para coletar relatórios, passe para p=quarantine e depois para p=reject quando todo remetente legítimo (plataforma de marketing, helpdesk, CRM) passar no alinhamento. Adicione registros MTA-STS e TLS-RPT para forçar a entrega criptografada aos seus servidores de e-mail. Em domínios que nunca enviam nem recebem e-mail, publique um MX nulo (MX 0 .), v=spf1 -all e um registro DMARC com p=reject: o MX nulo só diz que o domínio não aceita e-mail; são o SPF e o DMARC que permitem aos destinatários rejeitar falsificações. Verifique cada registro com o Verificador de SPF, o Verificador de DKIM e o Verificador de DMARC, e confira seus IPs de envio em listas de bloqueio com o Verificador de Blacklist de IP se a entregabilidade cair.
Registre logs, monitore e prepare-se para a invasão
Duas das dez categorias do OWASP 2025 tratam do que acontece depois de um erro: Security Logging and Alerting Failures (falhas de log e alerta de segurança, A09) e a nova Mishandling of Exceptional Conditions (tratamento inadequado de condições excepcionais, A10). A invasão típica ainda passa meses sem ser detectada porque as evidências nunca foram registradas, ou foram registradas e ninguém olhou.
- Registre eventos de segurança com contexto: todo login bem-sucedido ou com falha, alterações de MFA, redefinições de senha, mudanças de permissão, negações de controle de acesso, falhas de validação de entrada e ações administrativas, cada um com data e hora, ID do usuário, IP de origem e user agent.
- Nunca registre segredos em log: senhas, tokens de sessão, números completos de cartão, chaves de API. Mascare esses dados na camada de logging, e não em cada ponto de chamada.
- Envie os logs para fora do servidor, para um armazenamento central (CloudWatch, Loki, Elastic, um SIEM) com retenção de pelo menos 90 dias, para que um atacante com root não consiga apagar os próprios rastros.
- Crie alertas para padrões, não para eventos isolados: 50 logins com falha em um minuto, um pico de 403 vindo de uma sessão, um novo administrador criado fora do horário comercial, um certificado emitido para o seu domínio que você não solicitou.
- Falhe fechado: quando uma verificação downstream (serviço de autenticação, rate limiter, WAF) der erro, negue a requisição. A A10 existe porque muitos sistemas concedem acesso quando a verificação que deveria bloqueá-lo lança uma exceção.
- Monitore de fora: disponibilidade, expiração de certificados, mudanças de DNS, listagens em listas de bloqueio e regressões de cabeçalhos. Execute novamente o Verificador de SSL, o Verificador de Cabeçalhos HTTP e a Verificação de saúde DNS (40 verificações de delegação, servidores de nomes, DNSSEC e SPF/DMARC) após cada deploy.
Escreva o plano de resposta a incidentes antes de precisar dele
Decida com antecedência quem está de plantão, como trocar cada credencial, como colocar o site em modo somente leitura, onde estão os backups limpos e qual órgão regulador ou quais clientes precisam ser notificados e em quantas horas (72 pelo GDPR). Faça um exercício de simulação uma vez por ano. Um plano ensaiado transforma dias de improviso em uma lista de verificação.
Publique um arquivo security.txt em /.well-known/security.txt (RFC 9116) com uma linha Contact: e uma data Expires:, os dois campos obrigatórios (uma chave Encryption: é opcional). Pesquisadores que encontrarem uma falha no seu site vão procurar ali primeiro; sem ele, talvez não encontrem ninguém a quem avisar.
Teste tudo: scanners, pentests e verificações contínuas
Todos os controles acima podem ser verificados, e a verificação deve ser automatizada sempre que possível, para que não se degrade com o tempo. Uma escada razoável, do grátis e instantâneo ao periódico e pago:
| Verificação | Ferramenta | Com que frequência |
|---|---|---|
| Configuração, cadeia e expiração do TLS | Verificador de SSL, SSL Labs, testssl.sh | Após cada mudança de certificado ou de servidor; expiração diariamente |
| Cabeçalhos de segurança e CSP | Verificador de Cabeçalhos HTTP, MDN HTTP Observatory | Após cada deploy (coloque no CI) |
| Portas abertas | Verificador de Portas, nmap de fora da sua rede | Após cada mudança de firewall ou na nuvem |
| DNS, DNSSEC, autenticação de e-mail | Verificação de saúde DNS, Verificador de DMARC | Mensalmente e após qualquer edição no DNS |
| Subdomínios esquecidos | Localizador de Subdomínios | A cada trimestre e em toda desativação de serviço |
| Dependências com vulnerabilidades conhecidas | npm audit, Dependabot, Trivy | A cada build |
| Falhas no código (SAST) | Semgrep, CodeQL | A cada pull request |
| Vulnerabilidades web em tempo de execução (DAST) | ZAP, Nuclei | Semanalmente, no ambiente de staging |
| Autorização e lógica de negócio | Pentest manual ou programa de bug bounty | Anualmente e após grandes funcionalidades |
Scanners são bons em encontrar injeção, problemas de cabeçalhos e componentes desatualizados, e ruins em autorização e lógica de negócio, então reserve orçamento para pelo menos um teste feito por uma pessoa por ano em tudo o que lida com dinheiro ou dados pessoais. Corrija por nível de exposição: qualquer coisa que um usuário não autenticado consiga explorar pela internet vem primeiro.
Checklist de segurança web
Copie isto para o README do seu projeto ou para o seu gerenciador de tarefas. Cada linha é uma das práticas acima, redigida para ser marcada como feita ou não feita; a última coluna é a prova.
| Camada | Prática | Concluído quando |
|---|---|---|
| Domínio | Registrar lock e MFA na conta do registrador; renovação automática ativada | O WHOIS mostra clientTransferProhibited; expiração a mais de 12 meses |
| DNS | DNSSEC assinado; registro CAA listando apenas as suas CAs | dig +dnssec retorna RRSIG; registro DS presente na zona pai |
| DNS | Nenhum registro CNAME ou A órfão | Todo hostname do Localizador de Subdomínios resolve para algo que você controla |
| TLS | Apenas TLS 1.2+, TLS 1.3 de preferência, cadeia completa servida | Verificador de SSL: cadeia completa, TLS 1.0/1.1 recusados |
| TLS | HSTS com max-age de um ano e includeSubDomains (preload opcional) | O Verificador de Cabeçalhos HTTP passa no teste de HSTS |
| TLS | Renovação automatizada via ACME; expiração monitorada | certbot renew --dry-run passa; alerta configurado para 14 dias |
| Cabeçalhos | CSP (baseada em nonce), frame-ancestors, nosniff, Referrer-Policy, Permissions-Policy | Verificador de Cabeçalhos HTTP: nota A ou A+ |
| Autenticação | Hash com Argon2id ou bcrypt; regras de senha do NIST; verificação em lista de vazamentos | Um hash leva de 100 a 250 ms; nenhuma regra de composição |
| Autenticação | MFA oferecido a todos e obrigatório para administradores; passkeys suportadas | Login de administrador impossível sem um segundo fator |
| Autenticação | Endpoints de login, redefinição e MFA com rate limiting por IP e por conta | Seis tentativas rápidas de um IP: a sexta retorna 429 |
| Sessões | Cookie __Host- com Secure, HttpOnly e SameSite; ID trocado no login | Atributos do cookie visíveis no DevTools; sessão antiga inválida após o login |
| Entrada | Consultas parametrizadas em todo lugar; saída codificada por contexto; uploads validados pelo conteúdo | Nenhuma consulta montada com strings em uma busca no código; payloads de XSS aparecem como texto |
| Controle de acesso | Roteamento que nega por padrão; verificação de propriedade por objeto; CORS restrito | Repetir requisições com os IDs de outro usuário retorna 404 ou 403 |
| Dependências | Lockfile commitado; npm ci; auditoria no CI; actions fixadas por SHA; SRI em scripts de CDN | O build falha com uma CVE de alta severidade |
| Servidor | Apenas 80 e 443 públicas; SSH só com chaves; atualizações de segurança automáticas; segredos em variáveis de ambiente ou em um cofre | O Verificador de Portas mostra 3306 e 6379 como closed ou filtered, e a 22 também de fora do seu próprio intervalo |
| Backups | 3-2-1 com uma cópia imutável; restauração testada | Último teste de restauração bem-sucedido feito há menos de 90 dias |
SPF -all, DKIM, DMARC p=reject, MTA-STS | O Verificador de DMARC aprova; relatórios agregados chegando | |
| Monitoramento | Eventos de autenticação e autorização registrados de forma centralizada; alertas para padrões; monitoramento externo de uptime, certificados e DNS | Alerta de teste disparado e recebido |
| Resposta | Plano de incidentes por escrito; security.txt publicado; exercício tabletop realizado | Plano revisado nos últimos 12 meses |
Como isso se relaciona com o OWASP Top 10:2025
O OWASP Top 10 é a lista de riscos de aplicações web mais citada, e a edição de 2025 reorganizou a ordem e introduziu duas categorias novas. Se um cliente, auditor ou framework de compliance perguntar como você lida com ela, esta é a correspondência com as práticas deste guia:
| OWASP Top 10:2025 | Práticas neste guia |
|---|---|
| A01 Broken Access Control | Negar por padrão, verificações por objeto, CORS restrito, painéis de administração protegidos |
| A02 Security Misconfiguration | Cabeçalhos de segurança, HSTS, portas fechadas, cabeçalhos de versão removidos, listagem de diretórios desativada |
| A03 Software Supply Chain Failures (nova) | Lockfiles, auditorias, actions fixadas, SRI, SBOM, CI com privilégio mínimo |
| A04 Cryptographic Failures | TLS 1.2+ e 1.3, HSTS, Argon2id, gestão de segredos, backups criptografados |
| A05 Injection | Consultas parametrizadas, codificação de saída, CSP, validação de uploads |
| A06 Insecure Design | Modelagem de ameaças por camada, padrões que falham fechados, rate limiting desde o design |
| A07 Authentication Failures | Regras de senha do NIST, verificação de vazamentos, MFA e passkeys, rotação de sessão |
| A08 Software or Data Integrity Failures | SRI, dependências assinadas e fixadas, desserialização segura |
| A09 Security Logging and Alerting Failures | Logs centralizados, alertas por padrão de comportamento, monitoramento externo |
| A10 Mishandling of Exceptional Conditions (nova) | Falhar fechado, respostas de erro uniformes, nenhum stack trace exibido aos usuários |
O ASVS (Application Security Verification Standard) da OWASP transforma o mesmo material em um checklist numerado para auditorias. O Nível 1 é uma meta realista para qualquer site público; o Nível 2, para tudo o que lida com dados pessoais ou financeiros.
Verifique os cabeçalhos de segurança do seu site em segundos
O Verificador de Cabeçalhos HTTP gratuito do DNS Robot mostra os cabeçalhos de resposta de qualquer URL exatamente como o servidor os envia e pontua seus cabeçalhos de segurança com os testes do Mozilla HTTP Observatory, com a correção para cada um que estiver faltando. Sem cadastro.
Fontes
- 2026 Data Breach Investigations Report, Verizon
- OWASP Top 10:2025, OWASP
- Password Storage Cheat Sheet, OWASP
- SP 800-63B-4: Authentication and Authenticator Management, NIST
- Ballot SC-081v3: reducing certificate validity and data reuse periods, CA/Browser Forum
- HTTPS by default, Google
- RFC 9116: A File Format to Aid in Security Vulnerability Disclosure, IETF
Perguntas Frequentes sobre Boas Práticas de Segurança Web
Quais são as boas práticas de segurança web mais importantes?
O que é o OWASP Top 10 e ele ainda importa em 2026?
Quais cabeçalhos de segurança HTTP todo site deve enviar?
Só o HTTPS basta para deixar um site seguro?
Como armazenar senhas de usuários com segurança?
O que é Content Security Policy e o meu site precisa de uma?
Como verificar se o meu site segue as boas práticas de segurança web?
Por que a validade dos certificados TLS está ficando mais curta?
Com que frequência devo atualizar as dependências do meu site?
Sites pequenos realmente são atacados?
Artigos Relacionados
Ferramentas Relacionadas
Verificador de headers HTTP
Analise cabeçalhos de resposta HTTP e classificação de cabeçalhos de segurança
Verificador de Certificado SSL
Verifique a validade e detalhes de segurança do certificado SSL
Verificador de Portas
Teste a conectividade de portas e disponibilidade de serviços
Verificação de saúde DNS
Avalie o DNS: delegação, servidores de nomes, SOA, DNSSEC e e-mail em 40 testes
Verificador DMARC
Verifique a política DMARC e configurações de alinhamento de qualquer domínio
Localizador de Subdomínios
Descubra todos os subdomínios de qualquer domínio



