← Base de Conhecimento

BCrypt em Portais de Fornecedor: Segurança Real em Integrações B2B de Varejo

Um portal de fornecedores com 800 empresas cadastradas, acesso a precificação confidencial e notas fiscais — protegido por MD5 sem salt. Este artigo mostra como a auditoria revelou o problema e como a migração para BCrypt foi feita sem invalidar nenhuma senha existente.

Espaço Reservado · AdSense

MD5 em 2024: O Risco que Você Não Vê no Dashboard

O portal de fornecedores tinha sido desenvolvido em 2017 por uma equipe interna que não tinha segurança como prioridade — o foco era funcionalidade. Funcionou. Os fornecedores usavam, os pedidos de compra circulavam, as notas fiscais eram carregadas. Sete anos depois, o sistema ainda estava em produção, com 800+ fornecedores ativos, e ninguém havia revisado o mecanismo de autenticação.

A descoberta veio durante uma auditoria de segurança solicitada pelo cliente como pré-requisito para uma certificação ISO 27001. A query era direta: SELECT senha FROM usuarios LIMIT 10. As senhas eram hashes de 32 caracteres hexadecimais — MD5 puro, sem salt. Uma busca rápida em tabelas rainbow online encontrou 7 das 10 senhas em menos de 8 segundos.

O que tornava o risco concreto: o portal dava acesso a tabelas de preço de custo de produtos — informação que, nas mãos de um concorrente, valia muito. Um fornecedor mal-intencionado com acesso à conta de outro fornecedor podia ver toda a estrutura de margem da rede. MD5 sem salt não é um risco teórico — é uma vulnerabilidade que qualquer pessoa com um laptop e 15 minutos consegue explorar.

Por Que MD5 é Inadequado para Armazenamento de Senhas

MD5 foi projetado para verificação de integridade de arquivos — não para proteção de senhas. Três problemas fundamentais o tornam inadequado para autenticação:

  • Velocidade: MD5 é extremamente rápido — uma GPU moderna processa bilhões de hashes MD5 por segundo. Isso é ótimo para verificar um arquivo de 10GB, mas péssimo para senhas: um ataque de força bruta processa todos os candidatos a uma velocidade que torna senhas de até 8 caracteres trivialmente quebráveis em horas.
  • Rainbow tables: tabelas pré-computadas de hash→senha para as senhas mais comuns já estão disponíveis publicamente. "123456" em MD5 é e10adc3949ba59abbe56e057f20f883e — qualquer tabela rainbow tem esse mapeamento. Sem salt, qualquer senha fraca é imediatamente identificável.
  • Colisões: colisões em MD5 foram demonstradas em 2004. Embora colisões de senha sejam raras na prática, a existência de colisões computáveis é uma falha arquitetural que elimina MD5 de qualquer uso criptográfico sério.

Salt resolve parcialmente o problema de rainbow tables — um salt aleatório por usuário garante que o mesmo hash não aparece para dois usuários com a mesma senha. Mas salt não resolve o problema de velocidade: com sal, o atacante ainda processa bilhões de hashes por segundo, só precisa fazer isso individualmente para cada conta em vez de em lote.

Como BCrypt com Cost=12 Funciona

BCrypt foi projetado em 1999 especificamente para armazenamento de senhas. Seu diferencial é o work factor (custo): um parâmetro que controla quantas iterações o algoritmo executa. Cost 10 executa 2¹⁰ = 1.024 iterações. Cost 12 executa 2¹² = 4.096 iterações. Cost 14 executa 2¹⁴ = 16.384 iterações.

Na prática, BCrypt com cost=12 leva aproximadamente 250-400ms para gerar um hash em hardware moderno. Para um usuário legítimo fazendo login, isso é imperceptível. Para um atacante tentando 1 bilhão de senhas, 300ms por tentativa significa que a força bruta levaria séculos — não horas.

O hash BCrypt inclui o salt embutido na própria string de resultado: $2y$12$[22 chars de salt][31 chars de hash]. Você não precisa armazenar o salt separadamente — o hash BCrypt é auto-suficiente para verificação.

Use o Gerador de Hash para gerar hashes BCrypt com cost configurável e entender a estrutura do resultado antes de implementar em produção.

Migração Segura: Verify-Then-Rehash

O desafio de migrar um banco de senhas MD5 para BCrypt é que você não tem acesso às senhas em texto plano — só aos hashes. Não dá para simplesmente fazer hash de hash. A solução é a técnica verify-then-rehash, que migra as senhas gradualmente sem interromper o serviço e sem invalidar nenhuma conta existente.

O fluxo no momento do login:

  1. Usuário submete senha em texto plano
  2. Sistema verifica se o hash armazenado começa com $2y$ (BCrypt) ou tem 32 caracteres (MD5)
  3. Se MD5: calcula md5($senhaDigitada) e compara com o hash armazenado
  4. Se a senha está correta: imediatamente gera password_hash($senhaDigitada, PASSWORD_BCRYPT, ['cost' => 12]) e atualiza o banco
  5. Se BCrypt: usa password_verify($senhaDigitada, $hashArmazenado) diretamente

Com esse padrão, cada usuário que faz login migra automaticamente para BCrypt. Usuários que não fazem login permanecem com MD5 — mas após 90 dias, você pode forçar reset de senha para os que ainda não migraram. Em um portal B2B com 800 fornecedores ativos, a migração completa levou 47 dias com esse método passivo.

Performance de BCrypt em Alto Volume de Autenticações

BCrypt com cost=12 leva ~300ms por verificação. Em uma aplicação com 1.000 logins simultâneos, isso significa 1.000 threads bloqueadas por 300ms — o que pode ser um problema de capacidade dependendo da arquitetura.

Para portais B2B com picos de autenticação previsíveis (como o horário de abertura comercial às 8h), a solução é combinar BCrypt com um mecanismo de sessão robusto. Autentique com BCrypt uma vez, emita um token de sessão com validade de 8 horas, e as requisições subsequentes validam o token (operação de microsegundos) — não reautenticam com BCrypt.

O portal de fornecedores em questão tinha pico de 40 logins simultâneos — bem abaixo do limiar onde BCrypt se torna problema de performance. Para operações com dezenas de milhares de logins por hora, o Argon2id oferece melhor controle de paralelismo e consumo de memória.

Quando Usar Cost > 12

A recomendação do OWASP é ajustar o custo do BCrypt para que a operação leve pelo menos 1 segundo no hardware do servidor de produção. Se com cost=12 a operação leva 250ms, tente cost=13 (~500ms) ou cost=14 (~1s). Reavalie a configuração a cada 2 anos — hardware fica mais rápido, e o que levava 1 segundo em 2020 pode levar 100ms em 2026.

Perguntas Frequentes

BCrypt ou Argon2id para novos projetos?

Para novos projetos sem restrição de biblioteca, Argon2id é a recomendação atual do OWASP desde 2019. BCrypt é uma escolha sólida e amplamente suportada — mas Argon2id oferece parâmetros de memória e paralelismo que o tornam mais resistente a ataques de hardware especializado (GPUs e ASICs). BCrypt é a escolha conservadora e segura; Argon2id é a escolha moderna e defensivamente mais robusta.

SHA-256 com salt é suficiente para senhas?

Não. SHA-256, mesmo com salt, é muito rápido — e a velocidade é o inimigo do armazenamento seguro de senhas. Uma GPU moderna processa centenas de milhões de SHA-256 por segundo. O salt impede ataques de rainbow table, mas não desacelera ataques de força bruta. Use sempre algoritmos projetados para senhas: BCrypt, Argon2id, ou scrypt.

Como saber se minha aplicação está usando BCrypt ou MD5?

Consulte diretamente o banco de dados. Hashes BCrypt têm formato $2y$XX$ no início e 60 caracteres no total. Hashes MD5 têm 32 caracteres hexadecimais. Hashes SHA-1 têm 40 caracteres. Se você vê qualquer coisa diferente do padrão BCrypt ou Argon2id, a aplicação precisa ser migrada.

É necessário forçar troca de senha após migrar para BCrypt?

Não é tecnicamente necessário se a migração foi feita com verify-then-rehash — as senhas continuam válidas e são migradas automaticamente no próximo login. Mas é uma boa prática de segurança comunicar aos usuários que uma atualização de segurança foi realizada e encorajar a troca de senha, especialmente em portais com acesso a dados sensíveis. Forçar troca imediata é recomendado se houver suspeita de vazamento dos hashes MD5.

Caso Real: NuAto no Varejo

Em uma grande rede de atacarejo com centenas de lojas no estado de São Paulo, a NuAto conduziu uma auditoria de segurança no portal de fornecedores B2B — sistema que concentrava acesso a contratos de fornecimento, tabelas de preço de custo e notas fiscais eletrônicas de mais de 800 empresas fornecedoras. A auditoria foi motivada por uma exigência de seguro cibernético, não por um incidente — o que, em retrospecto, foi uma sorte.

A descoberta foi imediata: as senhas estavam armazenadas em MD5 sem salt, e o campo de senha no banco de dados não tinha nenhuma restrição de acesso além da autenticação de aplicação. Qualquer desenvolvedor com acesso ao banco de dados de produção — e havia quatro com esse acesso — podia trivialmente reverter as senhas da maioria dos fornecedores usando tabelas rainbow públicas. O plano de remediação priorizou três ações simultâneas: bloqueio de acesso direto ao banco por desenvolvedores (acesso via role específica com auditoria), implementação do verify-then-rehash em produção, e notificação dos fornecedores de que uma atualização de segurança havia sido realizada.

A migração via verify-then-rehash durou 47 dias para cobrir 94% dos usuários ativos. Os 6% restantes — fornecedores que não haviam feito login no período — receberam e-mail de reset forçado. O custo total da remediação foi estimado em 120 horas de desenvolvimento e 3 horas de comunicação. O custo hipotético de um vazamento de dados com as tabelas de preço de custo da rede — informação estratégica de alto valor competitivo — seria de ordem de magnitude maior, sem considerar as implicações da LGPD.

Carlos Zucolli

30 anos de experiência em varejo, marketing digital e desenvolvimento de soluções para o comércio brasileiro. Sócio da NuAto Comunicação e criador da Toolbox Dev Design. Já gerenciou campanhas para gigantes do Atacarejo, Home Center e Cooperativas de Consumo.

Ver perfil completo →
Espaço Reservado · AdSense
Espaço Publicitário