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

Boas práticas de segurança web em seis camadas: domínio e DNS, TLS, cabeçalhos HTTP, aplicação, dependências e servidor
Boas práticas de segurança web em seis camadas: domínio e DNS, TLS, cabeçalhos HTTP, aplicação, dependências e servidor
Comece a ler
  1. O que são boas práticas de segurança web
  2. A pilha de segurança web: seis camadas para proteger
  3. Camada 1: blinde o domínio e o DNS
  4. Camada 2: HTTPS e TLS bem configurados
  5. Camada 3: cabeçalhos de segurança HTTP
  6. Camada 4: autenticação que resiste ao credential stuffing
  7. Sessões, cookies e CSRF
  8. Injeção e XSS: valide a entrada, codifique a saída
  9. Broken Access Control: o risco número um
  10. Camada 5: dependências e a cadeia de suprimentos de software
  11. Camada 6: hardening do servidor (portas, patches, segredos, backups)
  12. Autenticação de e-mail: SPF, DKIM e DMARC
  13. Registre logs, monitore e prepare-se para a invasão
  14. Teste tudo: scanners, pentests e verificações contínuas
  15. Checklist de segurança web
  16. Como isso se relaciona com o OWASP Top 10:2025
  17. 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.

CamadaO que os atacantes fazem aquiPráticas essenciaisVerifique com
1. Domínio e DNSSequestram o domínio, trocam os nameservers, assumem subdomínios órfãos, obtêm certificados fraudulentosRegistrar lock, MFA, DNSSEC, CAA, auditoria de registros antigosConsulta 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 expiradosTLS 1.2+, HSTS (preload opcional), renovação automatizadaVerificador de SSL
3. Cabeçalhos HTTPInjetam scripts (XSS), colocam o site em frames para clickjacking, farejam tipos de conteúdo, vazam o referrerCSP, frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyVerificador de Cabeçalhos HTTP
4. AplicaçãoCredential stuffing, injeção, controle de acesso quebrado, CSRF, uploads insegurosArgon2id + MFA + rate limits, consultas parametrizadas, autorização no servidor, cookies SameSiteRevisão de código, ZAP, Testador de Força de Senha
5. DependênciasPacotes envenenados, CVEs conhecidas em bibliotecas, pipelines de CI comprometidosLockfiles, auditorias, versões fixadas, SBOM, tokens com privilégio mínimonpm audit, Dependabot, Trivy
6. Servidor e operaçõesPortas abertas, credenciais padrão, patches ausentes, nenhum backup, nenhum logFirewall, SSH só com chave, aplicação de patches, backups 3-2-1, logs centralizadosVerificador 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:

bash
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...C9

Restrinja 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:

dns
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:

bash
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.

http
Strict-Transport-Security: max-age=31536000; includeSubDomains

Certificados 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ênciaValidade máxima do certificadoReutilização da validação de domínio
Antes de 15 de março de 2026398 dias398 dias
15 de março de 2026200 dias200 dias
15 de março de 2027100 dias100 dias
15 de março de 202947 dias10 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'):

bash
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çalhoValor recomendadoO que ele previne
Strict-Transport-Securitymax-age=31536000; includeSubDomainsDowngrade de protocolo, roubo de cookies via HTTP
Content-Security-Policyscript-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-OptionsnosniffMIME sniffing que transforma um upload em script executável
Referrer-Policystrict-origin-when-cross-originVazamento de URLs completas (tokens, termos de busca) para terceiros
Permissions-Policycamera=(), microphone=(), geolocation=(), payment=()Scripts de terceiros usando em silêncio APIs poderosas do navegador
X-Frame-OptionsDENY (fallback legado para frame-ancestors)Clickjacking em navegadores sem CSP Level 2
Cross-Origin-Opener-Policysame-originAtaques 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.

http
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.
javascript
// 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
# 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:

  • Secure significa que o cookie nunca é enviado por HTTP puro, então ele não pode ser capturado em um Wi-Fi público.
  • HttpOnly deixa o cookie invisível para o JavaScript, então uma falha de XSS não consegue lê-lo.
  • SameSite=Lax (ou Strict para 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 seja Secure, tenha Path=/ e não tenha o atributo Domain, para que um subdomínio não consiga sobrescrevê-lo.
http
Set-Cookie: __Host-session=9f1c7e2a...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800

Açõ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).

javascript
// 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 caemCodifique comoExemplo
Corpo do HTMLEntidades HTML< vira &lt;, " vira &quot;
Atributo HTMLEntidades, com o atributo entre aspasSempre coloque o atributo entre aspas; codifique " e '
JavaScriptNã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 URLPercent-encodingencodeURIComponent(value)
Valor CSSEvite totalmente; escolha nomes de classe de uma allowlistNunca 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 qualquer Origin que 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.
javascript
// 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 com npm ci no 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 minimumReleaseAge do 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.
bash
# 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.

bash
# 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 ssh

No 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:

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çãoFerramentaCom que frequência
Configuração, cadeia e expiração do TLSVerificador de SSL, SSL Labs, testssl.shApós cada mudança de certificado ou de servidor; expiração diariamente
Cabeçalhos de segurança e CSPVerificador de Cabeçalhos HTTP, MDN HTTP ObservatoryApós cada deploy (coloque no CI)
Portas abertasVerificador de Portas, nmap de fora da sua redeApós cada mudança de firewall ou na nuvem
DNS, DNSSEC, autenticação de e-mailVerificação de saúde DNS, Verificador de DMARCMensalmente e após qualquer edição no DNS
Subdomínios esquecidosLocalizador de SubdomíniosA cada trimestre e em toda desativação de serviço
Dependências com vulnerabilidades conhecidasnpm audit, Dependabot, TrivyA cada build
Falhas no código (SAST)Semgrep, CodeQLA cada pull request
Vulnerabilidades web em tempo de execução (DAST)ZAP, NucleiSemanalmente, no ambiente de staging
Autorização e lógica de negócioPentest manual ou programa de bug bountyAnualmente 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.

CamadaPráticaConcluído quando
DomínioRegistrar lock e MFA na conta do registrador; renovação automática ativadaO WHOIS mostra clientTransferProhibited; expiração a mais de 12 meses
DNSDNSSEC assinado; registro CAA listando apenas as suas CAsdig +dnssec retorna RRSIG; registro DS presente na zona pai
DNSNenhum registro CNAME ou A órfãoTodo hostname do Localizador de Subdomínios resolve para algo que você controla
TLSApenas TLS 1.2+, TLS 1.3 de preferência, cadeia completa servidaVerificador de SSL: cadeia completa, TLS 1.0/1.1 recusados
TLSHSTS com max-age de um ano e includeSubDomains (preload opcional)O Verificador de Cabeçalhos HTTP passa no teste de HSTS
TLSRenovação automatizada via ACME; expiração monitoradacertbot renew --dry-run passa; alerta configurado para 14 dias
CabeçalhosCSP (baseada em nonce), frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyVerificador de Cabeçalhos HTTP: nota A ou A+
AutenticaçãoHash com Argon2id ou bcrypt; regras de senha do NIST; verificação em lista de vazamentosUm hash leva de 100 a 250 ms; nenhuma regra de composição
AutenticaçãoMFA oferecido a todos e obrigatório para administradores; passkeys suportadasLogin de administrador impossível sem um segundo fator
AutenticaçãoEndpoints de login, redefinição e MFA com rate limiting por IP e por contaSeis tentativas rápidas de um IP: a sexta retorna 429
SessõesCookie __Host- com Secure, HttpOnly e SameSite; ID trocado no loginAtributos do cookie visíveis no DevTools; sessão antiga inválida após o login
EntradaConsultas parametrizadas em todo lugar; saída codificada por contexto; uploads validados pelo conteúdoNenhuma consulta montada com strings em uma busca no código; payloads de XSS aparecem como texto
Controle de acessoRoteamento que nega por padrão; verificação de propriedade por objeto; CORS restritoRepetir requisições com os IDs de outro usuário retorna 404 ou 403
DependênciasLockfile commitado; npm ci; auditoria no CI; actions fixadas por SHA; SRI em scripts de CDNO build falha com uma CVE de alta severidade
ServidorApenas 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 cofreO Verificador de Portas mostra 3306 e 6379 como closed ou filtered, e a 22 também de fora do seu próprio intervalo
Backups3-2-1 com uma cópia imutável; restauração testadaÚltimo teste de restauração bem-sucedido feito há menos de 90 dias
E-mailSPF -all, DKIM, DMARC p=reject, MTA-STSO Verificador de DMARC aprova; relatórios agregados chegando
MonitoramentoEventos de autenticação e autorização registrados de forma centralizada; alertas para padrões; monitoramento externo de uptime, certificados e DNSAlerta de teste disparado e recebido
RespostaPlano de incidentes por escrito; security.txt publicado; exercício tabletop realizadoPlano 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:2025Práticas neste guia
A01 Broken Access ControlNegar por padrão, verificações por objeto, CORS restrito, painéis de administração protegidos
A02 Security MisconfigurationCabeç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 FailuresTLS 1.2+ e 1.3, HSTS, Argon2id, gestão de segredos, backups criptografados
A05 InjectionConsultas parametrizadas, codificação de saída, CSP, validação de uploads
A06 Insecure DesignModelagem de ameaças por camada, padrões que falham fechados, rate limiting desde o design
A07 Authentication FailuresRegras de senha do NIST, verificação de vazamentos, MFA e passkeys, rotação de sessão
A08 Software or Data Integrity FailuresSRI, dependências assinadas e fixadas, desserialização segura
A09 Security Logging and Alerting FailuresLogs 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

  1. 2026 Data Breach Investigations Report, Verizon
  2. OWASP Top 10:2025, OWASP
  3. Password Storage Cheat Sheet, OWASP
  4. SP 800-63B-4: Authentication and Authenticator Management, NIST
  5. Ballot SC-081v3: reducing certificate validity and data reuse periods, CA/Browser Forum
  6. HTTPS by default, Google
  7. 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?

Force HTTPS com TLS moderno e HSTS, envie cabeçalhos de segurança rígidos (principalmente uma Content Security Policy), faça o hash das senhas com Argon2id, protegido por MFA e rate limiting, use consultas parametrizadas e codificação de saída, imponha o controle de acesso no servidor para cada objeto, mantenha as dependências atualizadas e fixadas, feche as portas sem uso e registre os eventos de segurança de forma centralizada. Proteja o domínio e o DNS primeiro, porque todo o resto depende de você ainda controlar o seu nome.

O que é o OWASP Top 10 e ele ainda importa em 2026?

O OWASP Top 10 é um ranking mantido pela comunidade com os riscos de segurança mais críticos em aplicações web. A edição de 2025 lista Broken Access Control, Security Misconfiguration, Software Supply Chain Failures, Cryptographic Failures, Injection, Insecure Design, Authentication Failures, Software or Data Integrity Failures, Security Logging and Alerting Failures e Mishandling of Exceptional Conditions. Ele continua sendo a referência citada pela maioria das auditorias, frameworks e clientes.

Quais cabeçalhos de segurança HTTP todo site deve enviar?

No mínimo: Strict-Transport-Security, Content-Security-Policy (incluindo frame-ancestors), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin e Permissions-Policy. X-Frame-Options: DENY é um fallback legado para o frame-ancestors, e Cross-Origin-Opener-Policy: same-origin é um acréscimo barato. Remova Server e X-Powered-By para que os scanners não consigam ler as versões do seu software.

Só o HTTPS basta para deixar um site seguro?

Não. O HTTPS criptografa o tráfego entre o navegador e o servidor; ele não faz nada contra injeção, controle de acesso quebrado, senhas fracas, dependências vulneráveis ou uma porta de banco de dados aberta. É a camada básica, e o HSTS faz com que ela pegue: depois que um navegador viu o cabeçalho, ele nunca mais envia uma requisição HTTP simples ao seu domínio.

Como armazenar senhas de usuários com segurança?

Nunca em texto puro e nunca com um hash rápido como MD5 ou SHA-256. Use Argon2id (19 MiB de memória, 2 iterações) ou bcrypt com fator de trabalho 10 ou mais, com um salt único por senha, ajustado para que um hash leve cerca de 100 a 250 ms. Confira as senhas novas em uma lista de vazamentos e exija MFA para contas privilegiadas.

O que é Content Security Policy e o meu site precisa de uma?

A CSP é um cabeçalho HTTP que diz ao navegador de quais fontes uma página pode carregar scripts, estilos, frames e outros recursos. Uma CSP baseada em nonce com 'strict-dynamic' impede a maior parte do cross-site scripting mesmo quando existe uma falha de injeção. Todo site que exibe conteúdo enviado por usuários ou carrega scripts de terceiros deveria ter uma; comece no modo report-only e passe para o modo de bloqueio quando os relatórios de violação estiverem limpos.

Como verificar se o meu site segue as boas práticas de segurança web?

Comece pelas verificações de fora: uma verificação de SSL para versão de TLS, cadeia e expiração; uma verificação de cabeçalhos HTTP para os cabeçalhos de segurança; uma verificação de portas para serviços expostos; e uma verificação de saúde DNS para DNSSEC e SPF/DMARC. Depois escaneie as dependências com npm audit ou o equivalente da sua stack, rode o ZAP contra uma cópia de staging e teste manualmente o controle de acesso reenviando requisições como outro usuário.

Por que a validade dos certificados TLS está ficando mais curta?

O CA/Browser Forum votou por reduzir a validade máxima dos certificados de 398 dias para 200 dias (15 de março de 2026), 100 dias (15 de março de 2027) e 47 dias (15 de março de 2029), porque certificados mais curtos limitam o estrago de uma chave roubada ou de um certificado emitido indevidamente e reduzem a dependência da revogação. Na prática, a renovação precisa ser automatizada com ACME.

Com que frequência devo atualizar as dependências do meu site?

Aplique os patches de segurança assim que forem lançados, de preferência em até 24 horas para tudo o que estiver exposto à internet, e rode uma auditoria automatizada a cada build. Para atualizações que não são de segurança, esperar alguns dias é mais seguro, porque versões de pacotes comprometidas costumam ser retiradas rapidamente; ferramentas como o Renovate podem impor esse atraso automaticamente.

Sites pequenos realmente são atacados?

Sim, o tempo todo, porque os ataques são automatizados e não escolhem alvos pelo tamanho. Scanners varrem todos os endereços IP públicos em busca de portas abertas e vulnerabilidades conhecidas de CMS, e ferramentas de credential stuffing testam senhas vazadas em todo formulário de login que encontram. Um site pequeno também é valioso como hospedagem de phishing, relay de spam ou porta de entrada para um cliente maior.

Sobre o autor

Shaik Vahid

Fundador da DNS Robot. Vahid passou anos no suporte de hospedagem de sites resolvendo domínios, registros DNS, certificados SSL e entrega de e-mails para clientes. Ele cria as ferramentas da DNS Robot e escreve estes guias a partir dos erros que as pessoas realmente encontram.

Verificador de headers HTTP

Analise cabeçalhos de resposta HTTP e classificação de cabeçalhos de segurança