revision de seguridad FB, tokens, sesiones, roles. JWT

Issue #51 resolved
Nicolas Dimov created an issue

No description provided.

Comments (2)

  1. Adrian Paredes

    Hasta ahora estas son las pruebas y conclusiones que fui obteniendo de mi análisis:

    • Criticidad ALTA: El token JWT se guarda tanto en Front-End (en el LocalStorage) como en el Back-End (en Cookies). Es redundante y doblemente inseguro. Tenemos que elegir uno de los dos mecanismos y quedarnos con ése. Por la naturaleza de la aplicación puede ser que nos convenga más usar cookies, ya que no son vulnerables a ataques XSS. En cambio son vulnerables a ataques CSRF, pero Spring Boot nos cubre ese escenario.

    • Criticidad ALTA: En application.yml el secret (queenvictoria) es el mismo para todos los perfiles. Más allá de que queenvictoria habría que cambiarlo por un secret más complicado (podría ser un UUID), el secret debería ser distinto para cada uno de los ambientes en donde corra el servidor, así un usuario no puede intercambiar tokens de un ambiente al otro.

    • Criticidad MEDIA: Externalizar los properties sensibles de ambiente (ej: secret, usr/pass de la base, los secret de Facebook). Sobre todo para el ambiente productivo. Esto es de criticidad media (y no ALTA) porque para acceder a estos datos hay que tener el código fuente y en principio el código fuente sólo lo tiene gente de confianza. (Creo que con Spring Boot se puede externalizar el application.yml, o sobreescribirlo de forma fácil.)

    • Criticidad ALTA: La "sesión" de la aplicación expira cuando expira el token en lugar de expirar por inactividad. Por ejemplo: si se configura para que los token expiren a los 10 minutos, si el usuario está usando la aplicación o no, no importa, la app lo va a patear a los 10 minutos. Hice unas pruebas y parece que esto es así, pero todavía no estoy 100% seguro, porque sospecho que Spring Boot de todas formas maneja una sesión en el Tomcat. La pregunta acá es: ¿Estamos bien con eso? ¿O deberíamos asegurar que funcione más como una aplicación tradicional, cuya "sesión" muere por X tiempo de inactividad? (Tampoco vi que se esté usando el código de refresh del token, también podemos jugar con eso).

    • Criticidad ALTA: Hay una cookie (app.user_cookie: c_user) en donde también se guarda el Token JWT y, si no me equivoco, parece que no se está usando. La deberíamos borrar.

    • Criticidad BAJA: Para la salud de los desarrolladores, recomiendo habilitar el cross-domain para el header Access-Control-Allow-Origins. Esto ya vi cómo hacerlo. Podríamos tener como orígenes permitidos a http://localhost:3000 y http://localhost:4000 sólo para el profile dev. Esto evitaría tener que levantar Chrome en modo inseguro para correr la app desde NodeJS.

    • Criticidad ALTA: Hay variables que se están guardando en el LocalStorage del browser, como el usuario (con el token JWT dentro) y los authorities. Si vamos por el camino de usar cookies, tendríamos que deshacernos de estas variables. O por lo menos revisar que ninguno de los datos que se están guardando sean sensibles. Salvo los tokens, es debatible si información como el CBU, el DNI, o alguna otra es sensible, ya que de todas formas es info que se le muestra al usuario en la app, pero sí podría ser sensible la categoría del cliente y el grupo al que pertenece. Esta es alguna de la info que el usuario puede capturar simplemente viendo el localStorage en el Chrome: https://jsoneditoronline.org/?id=59199860fa56eede0f3cbe99d5f3f4d8.

    Estas son las pruebas que hice y salieron bien:

    • El servidor no debe confiar en ningún dato del cliente: Hasta donde pude verificar esto está bien. Lo único que recibe el servidor es el TokenJWT firmado con userId (en claim.sub). Una vez comprobada la firma, saca el userId y recupera los datos de la base de datos, incluso los authorities.

    • Probé de alterar el claim.exp del token y el backend me lo rebota porque no lo firmé con el secret. Genial!

    • Abrí el ARC (Advanced Rest Client) de Chrome y con mi token de authority USER probé de pegarle a /solicitud/aprobar. La respuesta que obtuve del server fue:

    { "timestamp": "2018-01-08T18:30:40.312+0000", "status": 403, "error": "Forbidden", "exception": "org.springframework.security.access.AccessDeniedException", "message": "Access is denied", "path": "/solicitud/aprobar" }

    Perfecto! Quiere decir que controla bien los authorities.

  2. Log in to comment