El método
En esta unidad has aprendido a transformar una API abierta en un sistema seguro, gobernado por la identidad y los privilegios.
Para proteger cualquier aplicación web profesional, aplica siempre este decálogo de seguridad:
- Asume la amnesia congénita de HTTP: cada petición llega aislada y debe demostrar su identidad en cada llamada.
- NUNCA almacenes contraseñas en claro ni cifradas: utiliza siempre funciones hash criptográficas lentas con Salt (BCrypt con factor de coste 12).
- Separa conceptual y técnicamente la Autenticación (AuthN: ¿quién eres?) de la Autorización (AuthZ: ¿qué puedes hacer?).
- Respeta la semántica de códigos HTTP: responde
401ante credenciales ausentes o inválidas y403ante permisos insuficientes. - Diseña formalmente una Matriz de Control de Acceso (RBAC) antes de escribir una sola línea de código de seguridad.
- Aplica el principio de seguridad por defecto mediante una
SecurityFilterChainfuncional en Spring Security 6. - Carga usuarios reales desde PostgreSQL desacoplando tu entidad JPA mediante el contrato
UserDetailsServiceyUserDetails. - Combina la seguridad perimetral de rutas con la seguridad en profundidad mediante anotaciones declarativas
@PreAuthorizey expresiones SpEL. - Elige con criterio técnico entre Sesión con Cookie (aplicaciones web tradicionales) o Token firmado JWT (APIs móviles y distribuidas sin estado).
- La seguridad nunca se fía del cliente: ocultar un botón en la interfaz es ergonomía; verificar el permiso en el backend es ingeniería.
La idea más importante
La seguridad nunca se implementa en el cliente; el navegador es un entorno que el usuario y el atacante controlan al 100 %. La única frontera real de una aplicación es el backend: toda regla de negocio, permiso y validación debe verificarse en el servidor en cada petición sin asumir jamás que el cliente es de confianza.
Ocultar botones o deshabilitar enlaces en una página web es una cortesía visual para que el usuario no se confunda. La verdadera seguridad consiste en que cuando un usuario intente saltarse esa interfaz y lanzar la petición a mano, el servidor detenga la operación en la frontera de red y responda con un muro infranqueable.
Las decisiones que tienes que saber justificar
| Decisión de ingeniería | Lo que tienes que poder defender ante un tribunal |
|---|---|
| BCrypt con factor 12 frente a SHA-256 | SHA-256 es ultrarrápido y vulnerable a ataques de fuerza bruta masivos con GPUs; BCrypt es deliberadamente lento, incluye Salt aleatorio contra tablas arcoíris y su coste computacional es adaptable en el tiempo. |
| Diferenciación semántica entre 401 y 403 | 401 indica falta de autenticación válida (el cliente puede reintentar aportando credenciales); 403 indica que la identidad está verificada pero carece de privilegios suficientes (prohibido). |
SecurityFilterChain funcional frente a herencia clásica |
WebSecurityConfigurerAdapter fue eliminado en Spring Boot 3; la configuración moderna mediante @Bean SecurityFilterChain con lambdas ofrece mayor modularidad y desacoplamiento. |
UserDetailsService sobre entidad JPA |
Desacopla la lógica interna del modelo de datos de la aplicación del contrato técnico de seguridad requerido por el motor de autenticación de Spring. |
@PreAuthorize con @EnableMethodSecurity |
Permite aplicar autorización granular junto al método de negocio, accediendo a los parámetros del método (#id) y evaluando reglas de propiedad a nivel de fila (SpEL). |
API sin estado (STATELESS) con JWT |
Permite escalabilidad horizontal inmediata sin balanceo con sesiones pegajosas ni dependencias de clústeres de memoria compartida (Redis). |
| No guardar datos confidenciales en el Payload del JWT | El Payload de un JWT solo está codificado en Base64Url y no cifrado; cualquier intermediario puede leer su contenido, por lo que solo debe contener identidades y roles. |
| Desactivación de CSRF solo en APIs con Bearer tokens | Los tokens Bearer viajan en cabeceras añadidas manualmente por JavaScript y los navegadores nunca las envían de forma automática, haciendo el ataque CSRF técnicamente inviable. |
| Orígenes explícitos en CORS al usar credenciales | El estándar W3C prohíbe el uso de allowedOrigins("*") junto a credenciales para evitar que cualquier sitio web malicioso secuestre sesiones autenticadas de usuarios. |
Pruebas automáticas con @WithMockUser |
Garantiza que las restricciones de seguridad están blindadas por tests automatizados que se ejecutan en milisegundos en pipelines de integración continua sin depender de bases de datos. |
Al terminar la unidad deberías poder responder
- ¿Por qué el protocolo HTTP es formalmente un protocolo sin estado (stateless)?
- ¿Cómo reconstruye el servidor la ilusión de continuidad mediante la cabecera
Set-Cookiey el identificadorJSESSIONID? - ¿Qué peligros de seguridad neutralizan las directivas
HttpOnly,SecureySameSiteen una cookie? - ¿Cuál es la diferencia exacta entre autenticación (AuthN) y autorización (AuthZ)?
- ¿En qué escenario exacto una API REST debe responder con código 401 y en cuál con 403?
- ¿Qué es una Matriz de Control de Acceso (RBAC) y qué roles estructuran el gestor de proyectos?
- ¿Por qué las contraseñas nunca deben guardarse mediante cifrado simétrico reversible (como AES)?
- ¿Por qué un algoritmo de hash rápido como SHA-256 o MD5 se considera hoy una negligencia para contraseñas?
- ¿Qué función cumple el Salt aleatorio en un hash de contraseñas y qué ataque previene?
- ¿Qué representa el formato modular
$2a$12$...en una cadena generada por BCrypt? - ¿Qué ocurre con todos los endpoints de una API inmediatamente después de añadir la dependencia de Spring Security?
- ¿Cómo intercepta la
SecurityFilterChainlas peticiones HTTP antes de que alcancen a los controladores? - ¿Qué contrato funcional exige la interfaz
UserDetailsServicey qué objeto devuelve? - ¿Cómo permite la anotación
@AuthenticationPrincipalinyectar al usuario activo en un controlador? - ¿Qué diferencia práctica existe entre comprobar
hasRole('ADMINISTRADOR')yhasAuthority('ROLE_ADMINISTRADOR')? - ¿Qué ventaja ofrece la anotación
@PreAuthorizefrente a definir reglas de seguridad solo por rutas URL? - ¿Qué tres partes componen la estructura de un JSON Web Token (JWT) y qué garantiza su firma?
- ¿Cuál es el compromiso (trade-off) más grave de usar JWTs puros sin estado respecto a la revocación de accesos?
- ¿Por qué un ataque de falsificación de peticiones en sitios cruzados (CSRF) solo afecta a sistemas basados en cookies?
- ¿Por qué el navegador bloquea una petición cross-origin si el backend tiene configurado
allowedOrigins("*")y el cliente envía credenciales?
El vocabulario de la unidad
| Concepto | Significa |
|---|---|
| Stateless | Característica de un protocolo o arquitectura donde el servidor no almacena ningún estado de sesión de los clientes entre peticiones consecutivas. |
| HttpSession | Mecanismo de los contenedores de servlets de Java para mantener atributos y contexto de un usuario en la memoria del servidor. |
| HttpOnly | Directiva de una cookie que prohíbe su acceso mediante código JavaScript (document.cookie), protegiéndola contra ataques XSS. |
| SameSite | Atributo de cookie que restringe su envío en peticiones originadas desde sitios web cruzados para neutralizar ataques CSRF. |
| Autenticación (AuthN) | Proceso de verificar la identidad declarada por un usuario o sistema mediante credenciales comprobables. |
| Autorización (AuthZ) | Proceso de determinar si una identidad autenticada dispone de los privilegios necesarios para ejecutar una acción sobre un recurso. |
| 401 Unauthorized | Código de estado HTTP que indica que la petición carece de credenciales de autenticación válidas para el recurso solicitado. |
| 403 Forbidden | Código de estado HTTP que indica que el servidor ha verificado la identidad del cliente pero este carece de permisos suficientes. |
| RBAC | Role-Based Access Control: modelo de seguridad donde los permisos se asignan a roles y los roles a usuarios. |
| BCrypt | Función hash criptográfica adaptativa unidireccional basada en el cifrado Blowfish, deliberadamente lenta para resistir fuerza bruta. |
| Salt | Secuencia aleatoria de bytes generada para cada usuario que se combina con su contraseña antes de computar el hash para evitar tablas precalculadas. |
| SecurityFilterChain | Cadena ordenada de filtros de Spring Security que intercepta e inspecciona cada petición HTTP entrante antes del controlador. |
| UserDetailsService | Interfaz central de Spring Security con el método loadUserByUsername() para recuperar credenciales y roles desde cualquier almacén de datos. |
| @PreAuthorize | Anotación de Spring Security que evalúa expresiones de seguridad (SpEL) antes de permitir la ejecución de un método en servicios o controladores. |
| JWT | JSON Web Token: estándar abierto (RFC 7519) que define un formato compacto y autónomo para transmitir información de forma segura mediante firmas criptográficas. |
| Bearer Token | Esquema de autenticación HTTP donde el portador del token demuestra su autorización simplemente presentándolo en la cabecera Authorization. |
| CSRF | Cross-Site Request Forgery: ataque que induce al navegador de una víctima autenticada a ejecutar acciones no deseadas en una aplicación web mediante cookies implícitas. |
Comprobación final del producto de la unidad
Auditoría de seguridad backend · criterios de producción
- Las contraseñas de los usuarios se almacenan exclusivamente con algoritmo BCrypt (factor de coste 12 o superior) y jamás en texto plano.
- La identidad y los roles de los usuarios residen en tablas persistentes de PostgreSQL y se cargan mediante
UserDetailsService. - Las cuentas de usuario desactivadas (
activo = false) son rechazadas automáticamente porisEnabled(). - La arquitectura de autorización distingue de forma estricta entre códigos
401 Unauthorizedy403 Forbidden. - Las rutas públicas de consulta y documentación (Swagger UI) están delimitadas sin exigir credenciales innecesarias.
- Las operaciones destructivas (creación, edición y borrado) están protegidas por roles con
@PreAuthorizeo matchers deSecurityFilterChain. - La aplicación implementa una estrategia justificada de autenticación (sesión segura con cookies o tokens JWT sin estado).
- Si se utiliza JWT, el token viaja en la cabecera
Authorization: Bearery la política de sesión esSTATELESS. - La configuración de CORS está integrada formalmente en Spring Security y restringe los orígenes a clientes autorizados sin comodines universales (
*). - La seguridad está respaldada por una suite de pruebas automatizadas con
MockMvcy@WithMockUserque pasa al 100 % en verde.
Resultados de la unidad
- Explicar por qué HTTP no mantiene estado y cómo lo resuelven cookies y sesión.
- Distinguir autenticación de autorización.
- Almacenar contraseñas con un algoritmo de hash adecuado.
- Proteger endpoints por rol y por permiso con Spring Security.
- Elegir entre sesión y token justificando la decisión.
- Reconocer y corregir los fallos habituales de CSRF y de CORS con credenciales.
Ya deberías ser capaz de
- Explicar por qué HTTP no mantiene estado y cómo lo resuelven cookies y sesión.
- Distinguir autenticación de autorización.
- Almacenar contraseñas con un algoritmo de hash adecuado.
- Proteger endpoints por rol y por permiso con Spring Security.
- Elegir entre sesión y token justificando la decisión.
- Reconocer y corregir los fallos habituales de CSRF y de CORS con credenciales.