Tu contraseña no es solo una cadena: por qué la autenticación en C# requiere un enfoque especial
\n\nImagina: has escrito una aplicación C# perfecta — con una interfaz bonita, consultas rápidas y una arquitectura limpia. Pero si la autenticación tiene fugas, todo el trabajo se va al traste. Los hackers no fuerzan puertas — encuentran las llaves. Y en el mundo moderno, la autenticación segura en C# no es una opción, sino una higiene básica del código.
\n\nEn este artículo, analizaremos no solo teoría, sino métodos reales de protección: desde el hash correcto de contraseñas hasta la implementación de JWT y OAuth. Aprenderás por qué SHA256 sin sal es malo, cómo no caer en ataques de fuerza bruta y qué hacer si tu proyecto ya ha superado los métodos de autenticación "para principiantes". ¡Allá vamos!
\n\nLos tres pilares de la seguridad: hash, sal y algoritmos lentos
\n\nEl antipatrón más común entre principiantes es almacenar contraseñas en texto plano o usar MD5 simple. Incluso si tienes "solo un proyecto de aprendizaje", el hábito se afianza. La autenticación segura en C# comienza con tres reglas:
\n\n- \n
- Nunca almacenes contraseñas en texto plano. Ni siquiera en una base de datos local. \n
- Usa una sal (salt) — una cadena aleatoria para cada usuario. \n
- Elige algoritmos lentos — BCrypt, PBKDF2, Argon2. \n
¿Por qué "lentos"? Porque un hacker necesita probar miles de millones de combinaciones por segundo. Si el hash toma 0.1 segundos, el ataque se vuelve económicamente inviable.
\n\nHash correcto de contraseñas en C# con BCrypt
\n\nBCrypt es el estándar de oro para desarrolladores .NET. Genera la sal automáticamente y la incrusta en el hash. No necesitas almacenar la sal por separado.
\n\nInstala el paquete a través de NuGet:
\nInstall-Package BCrypt.Net-Next\n\nAhora, un ejemplo de registro de usuario:
\n\nusing BCrypt.Net;\n\npublic class AuthService\n{\n public string HashPassword(string plainPassword)\n {\n // Work factor = 12 — equilibrio óptimo entre velocidad y seguridad\n return BCrypt.HashPassword(plainPassword, workFactor: 12);\n }\n\n public bool VerifyPassword(string plainPassword, string hashedPassword)\n {\n return BCrypt.Verify(plainPassword, hashedPassword);\n }\n}\n\n// Uso:\nvar auth = new AuthService();\nstring hash = auth.HashPassword("MyS3cur3P@ss!");\nbool isValid = auth.VerifyPassword("MyS3cur3P@ss!", hash); // true\n\nObserva: workFactor (factor de costo) determina cuántas iteraciones de hash se realizarán. 12 es un buen valor para 2024. Si tu servidor es potente, puedes subirlo a 13-14.
PBKDF2 — herramienta integrada en .NET
\n\nSi no quieres bibliotecas de terceros, usa Rfc2898DeriveBytes — la implementación integrada de PBKDF2 en .NET. Ejemplo:
using System.Security.Cryptography;\n\npublic static string HashWithPBKDF2(string password, byte[] salt, int iterations = 100_000)\n{\n using var deriveBytes = new Rfc2898DeriveBytes(password, salt, iterations, HashAlgorithmName.SHA256);\n byte[] hash = deriveBytes.GetBytes(32); // 32 bytes = 256 bits\n return Convert.ToBase64String(salt) + ":" + Convert.ToBase64String(hash);\n}\n\n// Generación de sal (16 bytes)\nbyte[] salt = RandomNumberGenerator.GetBytes(16);\nstring result = HashWithPBKDF2("userPassword", salt);\n\nImportante: no uses menos de 100 000 iteraciones. Las GPU modernas pueden probar millones de hashes por segundo.
\n\nJWT — autenticación moderna sin sesiones
\n\nCuando tu aplicación C# crece hasta convertirse en microservicios o SPA (React, Vue), almacenar sesiones en el servidor se vuelve incómodo. Aquí vienen al rescate los JSON Web Tokens (JWT) — tokens de acceso compactos y autónomos.
\n\nLa autenticación segura en C# con JWT se basa en tres principios:
\n- \n
- T