spring security - basada - ¿Tiene sentido asegurar una aplicación REST con una autenticación JWT y básica?
spring security rest token authentication (1)
Tengo una aplicación Spring REST que al principio estaba protegida con autenticación básica.
Luego agregué un controlador de inicio de sesión que crea un JWT JSON Web Token que se usa en solicitudes posteriores.
¿Podría mover el siguiente código del controlador de inicio de sesión al filtro de seguridad? Entonces no necesitaría el controlador de inicio de sesión por más tiempo.
tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail());
¿O podría eliminar la autenticación básica?
¿Es un buen diseño mezclar la autenticación básica con un JWT?
Aunque todo funciona bien, estoy un poco a oscuras aquí para diseñar mejor esta seguridad.
Asumiendo 100% de TLS para todas las comunicaciones, tanto durante como en todo momento después del inicio de sesión, la autenticación con nombre de usuario / contraseña a través de la autenticación básica y la recepción de un JWT a cambio es un caso de uso válido. Esto es casi exactamente cómo funciona uno de los flujos de OAuth 2 (''contraseña de concesión'').
La idea es que el usuario final se autentique a través de un punto final, por ejemplo, /login/token
utilizando el mecanismo que desee, y la respuesta debe contener el JWT que se enviará a todas las solicitudes posteriores. El JWT debe ser un JWS (es decir, un JWT firmado criptográficamente) con un campo de expiración JWT ( exp
) adecuado: esto asegura que el cliente no puede manipular el JWT o hacerlo vivir más de lo que debería.
Tampoco necesita un encabezado X-Auth-Token
: el esquema de Bearer
autenticación HTTP se creó para este caso de uso exacto: básicamente, cualquier bit de información que rastrea el nombre del esquema de Bearer
es información de "portador" que debe validarse. Usted acaba de configurar el encabezado de Authorization
:
Authorization: Bearer <JWT value here>
Pero, dicho esto, si su cliente REST no es de confianza (por ejemplo, navegador habilitado para JavaScript), ni siquiera haría eso: cualquier valor en la respuesta HTTP al que se pueda acceder mediante JavaScript, básicamente cualquier valor de encabezado o cuerpo de respuesta - podría ser olido e interceptado a través de ataques MITM XSS.
Es mejor almacenar el valor JWT en una cookie única y segura solo para HTTP (configuración de cookie: setSecure (true), setHttpOnly (true)). Esto garantiza que el navegador:
- solo transmita la cookie a través de una conexión TLS y,
- nunca haga que el valor de la cookie esté disponible para el código JavaScript.
Este enfoque es casi todo lo que necesita hacer para la seguridad de las mejores prácticas. Lo último es asegurarse de tener protección CSRF en cada solicitud HTTP para garantizar que los dominios externos que inician solicitudes en su sitio no puedan funcionar.
La forma más sencilla de hacerlo es configurar una cookie segura (pero no solo http) con un valor aleatorio, por ejemplo, un UUID.
Luego, en cada solicitud en su servidor, asegúrese de que su propio código de JavaScript lea el valor de la cookie y lo configure en un encabezado personalizado, por ejemplo X-CSRF-Token y verifique ese valor en cada solicitud en el servidor. Los clientes de dominio externo no pueden establecer encabezados personalizados para solicitudes a su dominio a menos que el cliente externo obtenga autorización a través de una solicitud de Opciones HTTP, por lo que cualquier intento de un ataque CSRF (por ejemplo, en un IFrame, lo que sea) les fallará.
Esta es la mejor seguridad disponible para clientes de JavaScript no confiables en la web hoy que conocemos. Stormpath también escribió un artículo sobre estas técnicas si tiene curiosidad.
Finalmente, el plugin Stormpath Java Servlet ya hace todo esto por ti (y muchas cosas más geniales, incluidas comprobaciones de seguridad automáticas adicionales), por lo que nunca tendrás que escribirlo, o lo que es peor, mantenerlo tú mismo. Consulte la sección Autenticación de solicitud HTTP y el ejemplo Form / Ajax para ver cómo usarlo. HTH!