¿Por qué Rust es la elección ideal para la autenticación?
\n\nSi estás escribiendo una aplicación web en Rust, ya estás un paso adelante en seguridad. Rust no perdona errores de memoria, lo que significa que muchas vulnerabilidades (desbordamiento de búfer, use-after-free) se eliminan en la etapa de compilación. Pero el compilador no te protegerá de una mala lógica de autenticación. De eso se trata este artículo: cómo construir autenticación segura en Rust utilizando prácticas modernas.
\n\nEn este artículo, montaremos un módulo de autenticación completo: hash de contraseñas con bcrypt, emisión de tokens JWT, verificación middleware en Actix-web y protección contra ataques típicos. El código será funcional: puedes usarlo directamente en tu proyecto.
1. Hash de contraseñas: ¿por qué bcrypt y no SHA-256?
\n\nMuchos principiantes piensan: "Usaré SHA-256, es rápido y confiable". Y ese es un error fatal. SHA es una función hash criptográfica, pero es demasiado rápida. Un atacante puede probar miles de millones de combinaciones por segundo. Necesitamos una función lenta, diseñada específicamente para contraseñas.
\n\nbcrypt es el estándar de oro. Incluye "sal" (salt) y un "factor de costo" (cost factor) que se puede aumentar a medida que crece la potencia computacional.
\n\nAñadiendo bcrypt a Cargo.toml
\n[dependencies]\nbcrypt = "0.15"\n\nHasheando la contraseña
\nuse bcrypt::{hash, verify, DEFAULT_COST};\n\nfn hash_password(plain: &str) -> Result<String, bcrypt::BcryptError> {\n hash(plain, DEFAULT_COST) // cost = 12 (por defecto)\n}\n\nfn verify_password(plain: &str, hashed: &str) -> bool {\n verify(plain, hashed).unwrap_or(false)\n}\n\nObserva: verify extrae la sal del hash por sí mismo. No necesitas almacenar la sal por separado, ya está dentro de la cadena del hash. Esto es seguro y conveniente.
2. Tokens JWT: cómo no fallar en la autenticación
\n\nDespués de que el usuario ingresa su contraseña, debemos emitirle un "pase". JWT (JSON Web Token) es un formato compacto y autónomo. Pero el diablo está en los detalles:
\n\n- \n
- No almacenes la clave secreta en el código. Usa variables de entorno. \n
- Establece una vida útil corta. Token de acceso: 15–30 minutos, token de actualización: 7–30 días. \n
- No insertes datos sensibles en el payload. Solo el ID del usuario y el rol. \n
Implementación de JWT con jsonwebtoken
\n\nuse jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};\nuse serde::{Serialize, Deserialize};\nuse chrono::{Utc, Duration};\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct Claims {\n pub sub: String, // ID del usuario\n pub exp: usize, // timestamp de expiración\n pub iat: usize, // emitido en\n}\n\npub fn create_token(user_id: &str, secret: &str) -> Result<String, jsonwebtoken::errors::Error> {\n let now = Utc::now();\n let claims = Claims {\n sub: user_id.to_owned(),\n exp: (now + Duration::minutes(30)).timestamp() as usize,\n iat: now.timestamp() as usize,\n };\n encode(&Header::default(), &claims, &EncodingKey::from_secret(secret.as_bytes()))\n}\n\npub fn validate_token(token: &str, secret: &str) -> Result<Claims, jsonwebtoken::errors::Error> {\n let token_data = decode::<Claims>(\n token,\n &DecodingKey::from_secret(secret.as_bytes()),\n &Validation::default(),\n )?;\n Ok(token_data.claims)\n}\n\n3. Uniendo todo: Actix-web + middleware
\n\nAhora conectemos el hash y JWT en una aplicación web completa con Actix-web. Escribiremos un middleware que verifique el token en cada solicitud protegida.
\n\nEstructura del proyecto
\nsrc/\n├── main.rs\n├── auth.rs # hash, JWT\n├── middleware.rs # verificación de token\n└── handlers.rs #