Autenticación segura en Java: cómo no reprobar el examen de seguridad

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: por qué tu contraseña no es solo una cadena

\n\n

Imagina: escribiste una aplicación Java genial para una biblioteca en línea. Los usuarios se registran, guardan marcadores, escriben reseñas. Y de repente — una fuga de la base de datos. Todas las contraseñas en texto plano. ¿Catástrofe? ¡Y de qué manera! En 2024, las filtraciones de datos ocurren cada 39 segundos, y el 81% de ellas están relacionadas con una autenticación débil. Si programas en Java y quieres que tu proyecto no termine en los titulares de cibernoticias — este artículo es para ti.

\n\n

Analizaremos la autenticación segura en aplicaciones Java de principio a fin: desde el hash de contraseñas hasta JWT y la protección contra CSRF. Sin teoría aburrida, solo código funcional y prácticas reales. ¡Vamos allá!

\n\n

1. Hash de contraseñas: la primera línea de defensa

\n\n

La primera regla de seguridad: nunca almacenes contraseñas en texto plano. Incluso si tu base de datos es el santo grial, el cifrado de contraseñas es el mínimo obligatorio. En Java se utilizan algoritmos como bcrypt, scrypt o Argon2. ¿Por qué no MD5 o SHA? Porque son demasiado rápidos — un atacante podría descifrar la contraseña en segundos.

\n\n

Práctica: bcrypt en acción

\n

Añade la dependencia en pom.xml (Maven):

\n
<dependency>\n    <groupId>org.springframework.security</groupId>\n    <artifactId>spring-security-crypto</artifactId>\n    <version>6.2.0</version>\n</dependency>\n
\n\n

Ahora hasheamos la contraseña al registrarse:

\n
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\n\npublic class PasswordService {\n    private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();\n\n    public String hashPassword(String rawPassword) {\n        return encoder.encode(rawPassword); // genera sal automáticamente\n    }\n\n    public boolean checkPassword(String rawPassword, String storedHash) {\n        return encoder.matches(rawPassword, storedHash);\n    }\n}\n
\n\n

Importante: bcrypt añade una sal aleatoria por sí mismo, por lo que incluso contraseñas idénticas se verán diferentes. El factor de costo (cost factor) por defecto es 10, pero para sistemas críticos se puede subir a 12-14.

\n\n

2. JWT (JSON Web Tokens): sesión ligera y segura

\n\n

Después del registro, el usuario debe confirmar su identidad de alguna manera. ¿Cookies? Se puede, pero JWT es el estándar moderno para APIs REST. El token contiene información sobre el usuario y está firmado con una clave secreta. Sin sesiones en el servidor — todo está en el token.

\n\n

Creación de JWT en Java

\n

Conecta la librería io.jsonwebtoken:jjwt:

\n
<dependency>\n    <groupId>io.jsonwebtoken</groupId>\n    <artifactId>jjwt-api</artifactId>\n    <version>0.12.3</version>\n</dependency>\n
\n\n

Generación del token:

\n
import io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.security.Keys;\nimport javax.crypto.SecretKey;\nimport java.util.Date;\n\npublic class JwtUtil {\n    private final SecretKey key = Keys.hmacShaKeyFor("clave_secreta_de_al_menos_256_bits".getBytes());\n\n    public String generateToken(String username) {\n        return Jwts.builder()\n                .subject(username)\n                .issuedAt(new Date())\n                .expiration(new Date(System.currentTimeMillis() + 3600000)) // 1 hora\n                .signWith(key)\n                .compact();\n    }\n\n    public String extractUsername(String token) {\n        return Jwts.parser()\n                .verifyWith(key)\n                .build()\n                .parseSignedClaims(token)\n                .getPayload()\n                .getSubject();\n    }\n}\n
\n\n

Consejo: ¡no almacenes la clave secreta en el código! Usa variables de entorno o Vault. Y nunca pongas datos confidenciales en JWT (contraseñas, números de tarjeta) — el token se puede decodificar sin la firma.

\n\n

3. Protección contra CSRF:

Blogs

Book Recommendations