bcrypt en Go: guía completa para el hash de contraseñas
La seguridad de los datos del usuario es una de las tareas fundamentales en el desarrollo web moderno. Almacenar contraseñas en texto plano es inaceptable, y el simple hash con MD5 o SHA-1 hace tiempo que se considera inseguro debido a su vulnerabilidad ante ataques de fuerza bruta. La librería bcrypt para Go ofrece un algoritmo de hash adaptativo robusto y probado, resistente tanto a ataques de diccionario como a aquellos que utilizan tablas rainbow.
El algoritmo bcrypt fue desarrollado en 1999 por Niels Provos y David Mazières, basándose en el cifrado Blowfish. Su característica clave es la complejidad adaptativa: puedes aumentar el número de iteraciones de hash, haciendo que la fuerza bruta sea cada vez más costosa a medida que crece la potencia de cálculo. En el ecosistema Go, la librería estándar golang.org/x/crypto/bcrypt es la extensión oficial y cuenta con el respaldo del equipo de desarrolladores de Go.
En este artículo, analizaremos en detalle todos los aspectos del trabajo con bcrypt en Go: desde la instalación y el uso básico hasta técnicas avanzadas y errores comunes. Aprenderás cómo hashear contraseñas correctamente, compararlas con sus hashes, elegir el costo óptimo e integrar bcrypt en aplicaciones reales.
Instalación
La librería bcrypt para Go no forma parte de la biblioteca estándar, pero es parte del submódulo oficial x/crypto. La instalación se realiza con un solo comando:
go get golang.org/x/crypto/bcrypt
Después de ejecutar este comando, aparecerá una dependencia en tu archivo go.mod y podrás importar el paquete en tu código:
import "golang.org/x/crypto/bcrypt"
Asegúrate de tener instalado Go versión 1.13 o superior (se recomienda 1.21+). Si usas módulos (el estándar en 2024), la dependencia se descargará automáticamente.
Inicio rápido: ejemplo mínimo funcional
Comencemos con el ejemplo más simple: hashear una contraseña y verificarla. Esta es la base que usarás en cualquier proyecto.
package main
import (
"fmt"
"log"
"golang.org/x/crypto/bcrypt"
)
func main() {
// Contraseña original del usuario
password := []byte("miClaveSecreta123!")
// Generamos el hash con el costo por defecto (10)
hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Hash de la contraseña: %s\n", hashedPassword)
// Verificamos la contraseña correcta
err = bcrypt.CompareHashAndPassword(hashedPassword, password)
if err != nil {
fmt.Println("¡La contraseña no coincide!")
} else {
fmt.Println("✓ ¡La contraseña coincide!")
}
// Verificamos una contraseña incorrecta
wrongPassword := []byte("contraseñaIncorrecta")
err = bcrypt.CompareHashAndPassword(hashedPassword, wrongPassword)
if err != nil {
fmt.Println("✗ La contraseña no coincide (como se esperaba)")
}
}
Este código hace tres cosas: genera un hash, verifica la contraseña correcta y confirma que la contraseña incorrecta es rechazada. Ten en cuenta que GenerateFromPassword genera automáticamente una sal aleatoria y la incorpora en el hash, por lo que cada vez obtendrás hashes diferentes para la misma contraseña.
Métodos y funciones principales
El paquete bcrypt ofrece una API pequeña pero muy bien diseñada. Veamos todas las funciones principales con ejemplos.
1. GenerateFromPassword
Firma: func GenerateFromPassword(password []byte, cost int) ([]byte, error)
Descripción: La función principal para hashear una contraseña. Recibe la contraseña como un slice de bytes y el costo (cost), un indicador logarítmico del número de iteraciones. Devuelve el hash en el formato estándar de bcrypt (incluye la sal, el costo y el hash en sí).
También en la biblioteca
Registro en Rust: revisión de las mejores bibliotecas y soluciones para tu proyecto
PyNaCl: Biblioteca de criptografía para Python
Geolocalización y mapas en C# (.NET): resumen de bibliotecas y herramientas