bcrypt em Go: guia completo para hash de senhas
A segurança dos dados do usuário é uma das principais preocupações no desenvolvimento web moderno. Armazenar senhas em texto puro é inaceitável, e usar hashing simples como MD5 ou SHA-1 é considerado inseguro devido à vulnerabilidade a ataques de força bruta. A biblioteca bcrypt para Go oferece um algoritmo de hash adaptativo robusto e testado pelo tempo, resistente tanto a ataques de dicionário quanto a ataques com tabelas rainbow.
O algoritmo bcrypt foi desenvolvido em 1999 por Niels Provos e David Mazières, baseado na cifra Blowfish. Sua principal característica é a complexidade adaptativa: você pode aumentar o número de iterações de hash, tornando a quebra de senhas cada vez mais custosa à medida que o poder computacional cresce. No ecossistema Go, a biblioteca padrão golang.org/x/crypto/bcrypt é uma extensão oficial mantida pela equipe de desenvolvimento do Go.
Neste artigo, vamos abordar todos os aspectos do uso de bcrypt em Go: desde a instalação e uso básico até técnicas avançadas e erros comuns. Você aprenderá como fazer hash de senhas corretamente, compará-las com hashes, escolher o custo ideal e integrar bcrypt em aplicações reais.
Instalação
A biblioteca bcrypt para Go não faz parte da biblioteca padrão, mas é um submódulo oficial do x/crypto. A instalação é feita com um único comando:
go get golang.org/x/crypto/bcrypt
Após executar este comando, a dependência será adicionada ao seu go.mod e você poderá importar o pacote no seu código:
import "golang.org/x/crypto/bcrypt"
Certifique-se de ter o Go versão 1.13 ou superior (recomendado 1.21+). Se você estiver usando módulos (padrão em 2024), a dependência será baixada automaticamente.
Início rápido: exemplo mínimo funcional
Vamos começar com o exemplo mais simples: gerar o hash de uma senha e verificá-lo. Esta é a base que você usará em qualquer projeto.
package main
import (
"fmt"
"log"
"golang.org/x/crypto/bcrypt"
)
func main() {
// Senha original do usuário
password := []byte("mySecretPassword123!")
// Gera o hash com o custo padrão (10)
hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Hash da senha: %s\n", hashedPassword)
// Verifica a senha correta
err = bcrypt.CompareHashAndPassword(hashedPassword, password)
if err != nil {
fmt.Println("Senha não confere!")
} else {
fmt.Println("✓ Senha confere!")
}
// Verifica uma senha incorreta
wrongPassword := []byte("senhaErrada")
err = bcrypt.CompareHashAndPassword(hashedPassword, wrongPassword)
if err != nil {
fmt.Println("✗ Senha não confere (como esperado)")
}
}
Este código faz três coisas: gera o hash, verifica a senha correta e confirma que uma senha incorreta é rejeitada. Observe que GenerateFromPassword gera automaticamente um salt aleatório e o incorpora no hash, portanto, cada execução produzirá hashes diferentes para a mesma senha.
Principais métodos e funções
O pacote bcrypt oferece uma API pequena, mas muito bem projetada. Vamos explorar todas as funções principais com exemplos.
1. GenerateFromPassword
Assinatura: func GenerateFromPassword(password []byte, cost int) ([]byte, error)
Descrição: Função principal para gerar o hash de uma senha. Recebe a senha como slice de bytes e o custo (cost) — um valor logarítmico que define o número de iterações. Retorna o hash no formato padrão bcrypt (contém salt, custo e o hash em si).